/** * アプリケーション再送の条件判定と短いスリープ処理 * * @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_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); } }
/** * コマンド受け取り時の処理 * @param pCmd */ void vProcessSerialCmd(tsSerCmd_Context *pCmd) { V_PRINTF(LB "! cmd len=%d data=", pCmd->u16len); int i; for (i = 0; i < pCmd->u16len && i < 8; i++) { V_PRINTF("%02X", pCmd->au8data[i]); } if (i < pCmd->u16len) { V_PRINTF("..."); } return; }
/**************************************************************************** * * NAME: cbvMcRxHandler * * DESCRIPTION: * * RETURNS: * ****************************************************************************/ PUBLIC void cbToCoNet_vRxEvent(tsRxDataApp *pRx) { int i; // print coming payload V_PRINTF( "\n\r[PKT Ad:%04x,Ln:%03d,Seq:%03d,Lq:%03d,Tms:%05d \"", pRx->u32SrcAddr, pRx->u8Len, // Actual payload byte: the network layer uses additional 4 bytes. pRx->u8Seq, pRx->u8Lqi, pRx->u32Tick & 0xFFFF); for (i = 0; i < pRx->u8Len; i++) { if (i < 32) { V_PUTCHAR((pRx->auData[i] >= 0x20 && pRx->auData[i] <= 0x7f) ? pRx->auData[i] : '.'); } else { V_PRINTF( ".."); break; } } V_PRINTF( "\"]"); // 直接受信したパケットを上位へ転送する if (pRx->auData[0] == 'T') { tsTxDataApp sTx; memset(&sTx, 0, sizeof(sTx)); sTx.u32DstAddr = TOCONET_NWK_ADDR_PARENT; sTx.u32SrcAddr = ToCoNet_u32GetSerial(); // Transmit using Long address sTx.u8Cmd = 0; // data packet. sTx.u8Seq = pRx->u8Seq; sTx.u8CbId = pRx->u8Seq; sTx.u16DelayMax = 300; // 送信開始の遅延を大きめに設定する memcpy(sTx.auData, pRx->auData, pRx->u8Len); sTx.auData[0] = 'R'; sTx.u8Len = pRx->u8Len; #ifdef USE_AES sTx.bSecurePacket = TRUE; #endif SPRINTF_vRewind(); vfPrintf(SPRINTF_Stream, ":%03d", pRx->u8Lqi); memcpy(sTx.auData + sTx.u8Len, SPRINTF_pu8GetBuff(), SPRINTF_u16Length()); sTx.u8Len += SPRINTF_u16Length(); ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx); } }
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); } }
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(); pEv->bKeepStateOnSetAll = FALSE; // スリープ復帰の状態を維持 // Mininode の場合、特別な処理は無いのだが、ポーズ処理を行う ToCoNet_Nwk_bPause(sAppData.pContextNwk); // センサー用の電源制御回路を Hi に戻す vPortSetSns(FALSE); #ifdef LITE2525A vPortSetLo(LED); #else vPortSetHi(LED); #endif // 周期スリープに入る if(sAppData.sFlash.sData.i16param == NORMAL || sAppData.sFlash.sData.i16param == NEKOTTER ){ vSleep(sAppData.sFlash.sData.u32Slp, sAppData.u16frame_count == 1 ? FALSE : TRUE, FALSE); }else{ // 割り込みの設定 vAHI_DioSetDirection(PORT_INPUT_MASK_ADXL345, 0); // set as input (void)u32AHI_DioInterruptStatus(); // clear interrupt register vAHI_DioWakeEnable(PORT_INPUT_MASK_ADXL345, 0); // also use as DIO WAKE SOURCE vAHI_DioWakeEdge(PORT_INPUT_MASK_ADXL345, 0); // 割り込みエッジ(立上がりに設定) vSleep(0, FALSE, FALSE); } } }
/* スリープをする状態 */ 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); // print message. vAHI_UartDisable(UART_PORT); // UART を解除してから(このコードは入っていなくても動作は同じ) // set UART Rx port as interrupt source vAHI_DioSetDirection(PORT_INPUT_MASK, 0); // set as input (void)u32AHI_DioInterruptStatus(); // clear interrupt register vAHI_DioWakeEnable(PORT_INPUT_MASK, 0); // also use as DIO WAKE SOURCE // i16paramに関わらず状態の変化で起床 if(sAppData.bDI1_Now_Opened) { vAHI_DioWakeEdge(0, PORT_INPUT_MASK); // 割り込みエッジ(立下りに設定) } else { vAHI_DioWakeEdge(PORT_INPUT_MASK, 0); // 割り込みエッジ(立上がりに設定) } // wake up using wakeup timer as well. ToCoNet_vSleep(E_AHI_WAKE_TIMER_0, sAppData.sFlash.sData.u32Slp, FALSE, FALSE ); // PERIODIC RAM OFF SLEEP USING WK0 } }
/**************************************************************************** * * NAME: cbToCoNet_vNwkEvent * * DESCRIPTION: * * PARAMETERS: Name RW Usage * * RETURNS: * * NOTES: ****************************************************************************/ void cbToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg) { switch(eEvent) { case E_EVENT_TOCONET_NWK_START: A_PRINTF( LB"[E_EVENT_TOCONET_NWK_START]"); break; case E_EVENT_TOCONET_NWK_DISCONNECT: A_PRINTF( LB"[E_EVENT_TOCONET_NWK_DISCONNECT]"); break; case E_EVENT_TOCONET_NWK_ROUTE_PKT: if (u32arg) { tsRoutePktInfo *pInfo = (void*)u32arg; if (pInfo->bUpstream) { sAppData.u32LedCt = u32TickCount_ms; } } break; case E_EVENT_TOCONET_NWK_MESSAGE_POOL_REQUEST: sAppData.u32LedCt = u32TickCount_ms; break; case E_EVENT_TOCONET_NWK_MESSAGE_POOL: if (u32arg) { tsToCoNet_MsgPl_Entity *pInfo = (void*)u32arg; int i; uint8 u8buff[TOCONET_MOD_MESSAGE_POOL_MAX_MESSAGE+1]; memcpy(u8buff, pInfo->au8Message, pInfo->u8MessageLen); u8buff[pInfo->u8MessageLen] = 0; A_PRINTF( "[MSGPOOL sl=%d ln=%d msg=", pInfo->u8Slot, pInfo->u8MessageLen ); for (i = 0; i < pInfo->u8MessageLen; i++) { A_PRINTF("%02X", u8buff[i]); } A_PRINTF("]"LB); } break; case E_EVENT_TOCONET_PANIC: if (u32arg) { tsPanicEventInfo *pInfo = (void*)u32arg; V_PRINTF( "PANIC DETECTED!"); pInfo->bCancelReset = TRUE; } break; default: break; } }
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); // スリープ状態へ遷移 } }
/**************************************************************************** * * NAME: cbvMcEvTxHandler * * DESCRIPTION: * * PARAMETERS: Name RW Usage * * RETURNS: * * NOTES: ****************************************************************************/ PUBLIC void cbToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) { V_PRINTF( LB ">>> MacAck%s(tick=%d,req=#%d) <<<", bStatus ? "Ok" : "Ng", u32TickCount_ms & 0xFFFF, u8CbId ); return; }
/* * 最初に遷移してくる状態 */ 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); } } }
/** * 送信完了待ち * * @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); // 再送条件へ遷移 } }
static int slackspace_test(int verbose) { unsigned ksize, vsize; int ksizes[] = { sizeof( ((small_title_chunk_t*) 0)->data ) - 1, sizeof( ((small_title_chunk_t*) 0)->data ), sizeof( ((small_title_chunk_t*) 0)->data ) + 1, ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 2) * sizeof( ((small_body_chunk_t*) 0)->data ) ) - 1, ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 2) * sizeof( ((small_body_chunk_t*) 0)->data ) ), ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 2) * sizeof( ((small_body_chunk_t*) 0)->data ) ), }; V_LPRINTF(1, "%s\n", __FUNCTION__); for (vsize = 0; vsize < 16 * 1024; vsize ++) { for (ksize = 0; ksize < (sizeof(ksizes) / sizeof(*ksizes)); ksize ++) { size_t slack = slackspace(ksizes[ksize], vsize); if (vsize % 1024 == 0) { V_PRINTF(2, "\r * allocating object value size=%u", vsize); V_FLUSH(2); } if (vsize == 0 && ksizes[ksize] == 0) { continue; } TASSERT( is_large_chunk(ksizes[ksize], vsize) == is_large_chunk(ksizes[ksize], vsize + slack) ); TASSERT( chunks_needed(ksizes[ksize], vsize) == chunks_needed(ksizes[ksize], vsize + slack) ); } } V_PRINTF(2, "\n"); return 0; }
/* * ADC 計測をしてデータ送信するアプリケーション制御 */ PRSEV_HANDLER_DEF(E_STATE_IDLE, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { 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); } // RC クロックのキャリブレーションを行う ToCoNet_u16RcCalib(sAppData.sFlash.sData.u16RcClock); // センサーがらみの変数の初期化 u8sns_cmplt = 0; // LIS3DH の初期化 vLIS3DH_Init( &sObjLIS3DH, &sSnsObj ); vSnsObj_Process(&sSnsObj, E_ORDER_KICK); if (bSnsObj_isComplete(&sSnsObj)) { // 即座に完了した時はセンサーが接続されていない、通信エラー等 u8sns_cmplt |= E_SNS_LIS3DH_CMP; V_PRINTF(LB "*** LIS3DH 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_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(); pEv->bKeepStateOnSetAll = FALSE; // スリープ復帰の状態を維持 // Mininode の場合、特別な処理は無いのだが、ポーズ処理を行う ToCoNet_Nwk_bPause(sAppData.pContextNwk); // センサー用の電源制御回路を Hi に戻す vPortSetSns(FALSE); // 周期スリープに入る // - 初回は5秒あけて、次回以降はスリープ復帰を基点に5秒 vSleep(sAppData.sFlash.sData.u32Slp, sAppData.u16frame_count == 1 ? FALSE : TRUE, FALSE); } }
static void vProcessTSL2561(teEvent eEvent) { if (bSnsObj_isComplete(&sSnsObj)) { return; } // イベントの処理 vSnsObj_Process(&sSnsObj, eEvent); // ポーリングの時間待ち if (bSnsObj_isComplete(&sSnsObj)) { u8sns_cmplt |= E_SNS_TSL2561_CMP; V_PRINTF(LB"!TSL2561: %dC", sObjTSL2561.u32Result ); // 完了時の処理 if (u8sns_cmplt == E_SNS_ALL_CMP) { ToCoNet_Event_Process(E_ORDER_KICK, 0, vProcessEvCore); } } }
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); // センサー用の電源制御回路を Hi に戻す vPortSetSns(FALSE); #ifdef LITE2525A vPortSetLo(LED); #else vPortSetHi(LED); #endif vAHI_DioWakeEnable(0, PORT_INPUT_MASK); // DISABLE DIO WAKE SOURCE ToCoNet_vSleep( E_AHI_WAKE_TIMER_0, sAppData.sFlash.sData.u32Slp, FALSE, FALSE); } }
/* * 送信後のチャタリング対策を行う状態 */ 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); // スリープ状態へ遷移 } }
static void vProcessBME280(teEvent eEvent) { if (bSnsObj_isComplete(&sSnsObj)) { return; } // イベントの処理 vSnsObj_Process(&sSnsObj, eEvent); // ポーリングの時間待ち if (bSnsObj_isComplete(&sSnsObj)) { u8sns_cmplt |= E_SNS_BME280_CMP; V_PRINTF(LB"!BME280: Temp : %d, Hum : %d, Pres : %d", sObjBME280.i16Temp, sObjBME280.u16Hum, sObjBME280.u16Pres ); // 完了時の処理 if (u8sns_cmplt == E_SNS_ALL_CMP) { ToCoNet_Event_Process(E_ORDER_KICK, 0, vProcessEvCore); } } }
/** * スリープへの遷移 * * @param E_STATE_APP_SLEEP * @param pEv * @param eEvent * @param u32evarg */ PRSEV_HANDLER_DEF(E_STATE_APP_SLEEP, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_EVENT_NEW_STATE) { pEv->bKeepStateOnSetAll = FALSE; u8RetryCount = 0xff; // センサー用の電源制御回路を Hi に戻す vPortSetSns(FALSE); // RTS0 を通信禁止にする vPortSetHi(PORT_RTS0); // Sleep は必ず E_EVENT_NEW_STATE 内など1回のみ呼び出される場所で呼び出す。 V_PRINTF(LB"Sleeping..."); V_FLUSH(); // Mininode の場合、特別な処理は無いのだが、ポーズ処理を行う ToCoNet_Nwk_bPause(sAppData.pContextNwk); // スリープ状態に遷移 vSleep(0, FALSE, FALSE); } }
static void vProcessLIS3DH(teEvent eEvent) { if (bSnsObj_isComplete(&sSnsObj)) { return; } // イベントの処理 vSnsObj_Process(&sSnsObj, eEvent); // ポーリングの時間待ち if (bSnsObj_isComplete(&sSnsObj)) { u8sns_cmplt |= E_SNS_LIS3DH_CMP; V_PRINTF(LB"!LIS3DH: X : %d, Y : %d, Z : %d", sObjLIS3DH.ai16Result[LIS3DH_IDX_X], sObjLIS3DH.ai16Result[LIS3DH_IDX_Y], sObjLIS3DH.ai16Result[LIS3DH_IDX_Z] ); // 完了時の処理 if (u8sns_cmplt == E_SNS_ALL_CMP) { ToCoNet_Event_Process(E_ORDER_KICK, 0, vProcessEvCore); } } }
/**************************************************************************** * * 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; } }
/* * allocate all memory with small and large chunks. link them such the * allocation of a large object will start evicting small chunks but then stop * because the large chunk LRU has an older item. this covers part of case 3 * and part of case 4 for the small item alloc in flat_storage_lru_evict(..). */ static int mixed_items_release_small_and_large_items_scan_stop_test(int verbose) { typedef struct { item* it; char key[KEY_MAX_LENGTH]; uint8_t klen; } mixed_items_release_one_small_item_t; size_t num_small_objects = (fsi.large_free_list_sz / 2) * SMALL_CHUNKS_PER_LARGE_CHUNK; /* this is not the same as fsi.large_free_list_sz / 2 due to rounding. */ size_t num_large_objects = fsi.large_free_list_sz - (fsi.large_free_list_sz / 2); mixed_items_release_one_small_item_t* large_items = malloc(sizeof(mixed_items_release_one_small_item_t) * num_large_objects); mixed_items_release_one_small_item_t* small_items = malloc(sizeof(mixed_items_release_one_small_item_t) * num_small_objects); item* lru_trigger; size_t max_small_key_size = SMALL_TITLE_CHUNK_DATA_SZ; size_t min_size_for_large_chunk = ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 1) * sizeof( ((small_body_chunk_t*) 0)->data ) ) + 1; size_t i; char key[KEY_MAX_LENGTH]; size_t klen; size_t large_free_list_sz = fsi.large_free_list_sz, small_free_list_sz = fsi.small_free_list_sz; V_PRINTF(1, " * %s\n", __FUNCTION__); TASSERT(fsi.large_free_list_sz != 0); TASSERT(fsi.small_free_list_sz == 0); for (i = 0; i < num_small_objects; i ++) { V_PRINTF(2, "\r * allocating small object %lu", i); V_FLUSH(2); do { small_items[i].klen = make_random_key(small_items[i].key, max_small_key_size, true); } while (assoc_find(small_items[i].key, small_items[i].klen)); small_items[i].it = do_item_alloc(small_items[i].key, small_items[i].klen, FLAGS, 0, 0, addr); TASSERT(small_items[i].it); TASSERT(is_item_large_chunk(small_items[i].it) == 0); do_item_link(small_items[i].it, small_items[i].key); } V_PRINTF(2, "\n"); for (i = 0; i < num_large_objects; i ++) { V_PRINTF(2, "\r * allocating large object %lu", i); V_FLUSH(2); do { large_items[i].klen = make_random_key(large_items[i].key, KEY_MAX_LENGTH, true); } while (assoc_find(large_items[i].key, large_items[i].klen)); large_items[i].it = do_item_alloc(large_items[i].key, large_items[i].klen, FLAGS, 0, min_size_for_large_chunk - large_items[i].klen, addr); TASSERT(large_items[i].it); TASSERT(is_item_large_chunk(large_items[i].it)); do_item_link(large_items[i].it, large_items[i].key); } V_PRINTF(2, "\n"); TASSERT(fsi.large_free_list_sz == 0 && fsi.small_free_list_sz == 0); V_LPRINTF(2, "update items\n"); /* update the objects we want to clobber *first*. but since ties go to the * large item, we need to bump the time stamp to ensure the small item is * released first. */ current_time += ITEM_UPDATE_INTERVAL + 1; /* initial bump to ensure that * LRU reordering takes place. */ do_item_update(small_items[0].it); current_time += 1; do_item_update(large_items[0].it); /* bump the timestamp and add the remaining items. */ current_time += 1; for (i = 1; i < num_small_objects; i ++) { do_item_update(small_items[i].it); } for (i = 1; i < num_large_objects; i ++) { do_item_update(large_items[i].it); } V_LPRINTF(2, "dereferencing objects\n"); for (i = 0; i < num_small_objects; i ++) { do_item_deref(small_items[i].it); } for (i = 0; i < num_large_objects; i ++) { do_item_deref(large_items[i].it); } V_LPRINTF(2, "alloc after deref\n"); do { klen = make_random_key(key, max_small_key_size, true); } while (assoc_find(key, klen)); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, LARGE_TITLE_CHUNK_DATA_SZ - klen, addr); TASSERT(lru_trigger != NULL); TASSERT(is_item_large_chunk(lru_trigger)); V_LPRINTF(2, "search for evicted objects\n"); TASSERT(assoc_find(small_items[0].key, small_items[0].klen) == NULL); TASSERT(assoc_find(large_items[0].key, large_items[0].klen) == NULL); V_LPRINTF(2, "ensuring that objects that shouldn't be evicted are still present\n"); for (i = 1; i < num_small_objects; i ++) { TASSERT(assoc_find(small_items[i].key, small_items[i].klen)); } for (i = 1; i < num_large_objects; i ++) { TASSERT(assoc_find(large_items[i].key, large_items[i].klen)); } V_LPRINTF(2, "cleanup objects\n"); for (i = 1; i < num_small_objects; i ++) { do_item_unlink(small_items[i].it, UNLINK_NORMAL, small_items[i].key); } for (i = 1; i < num_large_objects; i ++) { do_item_unlink(large_items[i].it, UNLINK_NORMAL, large_items[i].key); } do_item_deref(lru_trigger); TASSERT(fsi.large_free_list_sz == large_free_list_sz && fsi.small_free_list_sz == small_free_list_sz); return 0; }
/* * allocate all memory with small and large chunks. link them such that the * small items are the oldest. allocate one large object that can be covered by * the release of one large item. this covers part of case 4 for the large item * alloc in flat_storage_lru_evict(..). */ static int mixed_items_release_one_large_item_test(int verbose) { typedef struct { item* it; char key[KEY_MAX_LENGTH]; uint8_t klen; } mixed_items_release_one_small_item_t; size_t num_small_objects = (fsi.large_free_list_sz / 2) * SMALL_CHUNKS_PER_LARGE_CHUNK; /* this is not the same as fsi.large_free_list_sz / 2 due to rounding. */ size_t num_large_objects = fsi.large_free_list_sz - (fsi.large_free_list_sz / 2); mixed_items_release_one_small_item_t* large_items = malloc(sizeof(mixed_items_release_one_small_item_t) * num_large_objects); mixed_items_release_one_small_item_t* small_items = malloc(sizeof(mixed_items_release_one_small_item_t) * num_small_objects); item* lru_trigger; size_t max_small_key_size = SMALL_TITLE_CHUNK_DATA_SZ; size_t min_size_for_large_chunk = ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 1) * sizeof( ((small_body_chunk_t*) 0)->data ) ) + 1; size_t i; char key[KEY_MAX_LENGTH]; size_t klen; size_t large_free_list_sz = fsi.large_free_list_sz, small_free_list_sz = fsi.small_free_list_sz; V_PRINTF(1, " * %s\n", __FUNCTION__); TASSERT(fsi.large_free_list_sz != 0); TASSERT(fsi.small_free_list_sz == 0); for (i = 0; i < num_large_objects; i ++) { V_PRINTF(2, "\r * allocating large object %lu", i); V_FLUSH(2); do { large_items[i].klen = make_random_key(large_items[i].key, KEY_MAX_LENGTH, true); } while (assoc_find(large_items[i].key, large_items[i].klen)); large_items[i].it = do_item_alloc(large_items[i].key, large_items[i].klen, FLAGS, 0, min_size_for_large_chunk - large_items[i].klen, addr); TASSERT(large_items[i].it); TASSERT(is_item_large_chunk(large_items[i].it)); do_item_link(large_items[i].it, large_items[i].key); } V_PRINTF(2, "\n"); for (i = 0; i < num_small_objects; i ++) { V_PRINTF(2, "\r * allocating small object %lu", i); V_FLUSH(2); do { small_items[i].klen = make_random_key(small_items[i].key, max_small_key_size, true); } while (assoc_find(small_items[i].key, small_items[i].klen)); small_items[i].it = do_item_alloc(small_items[i].key, small_items[i].klen, FLAGS, 0, 0, addr); TASSERT(small_items[i].it); TASSERT(is_item_large_chunk(small_items[i].it) == 0); do_item_link(small_items[i].it, small_items[i].key); } V_PRINTF(2, "\n"); TASSERT(fsi.large_free_list_sz == 0 && fsi.small_free_list_sz == 0); V_LPRINTF(2, "alloc before deref\n"); do { klen = make_random_key(key, max_small_key_size, true); } while (assoc_find(key, klen)); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, 0, addr); TASSERT(lru_trigger == NULL); V_LPRINTF(2, "dereferencing objects\n"); for (i = 0; i < num_small_objects; i ++) { do_item_deref(small_items[i].it); } for (i = 0; i < num_large_objects; i ++) { do_item_deref(large_items[i].it); } V_LPRINTF(2, "alloc after deref\n"); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, min_size_for_large_chunk - klen, addr); TASSERT(lru_trigger != NULL); V_LPRINTF(2, "search for evicted object\n"); TASSERT(assoc_find(large_items[0].key, large_items[0].klen) == NULL); V_LPRINTF(2, "ensuring that objects that shouldn't be evicted are still present\n"); for (i = 0; i < num_small_objects; i ++) { TASSERT(assoc_find(small_items[i].key, small_items[i].klen)); } for (i = 1; i < num_large_objects; i ++) { TASSERT(assoc_find(large_items[i].key, large_items[i].klen)); } V_LPRINTF(2, "cleanup objects\n"); for (i = 0; i < num_small_objects; i ++) { do_item_unlink(small_items[i].it, UNLINK_NORMAL, small_items[i].key); } for (i = 1; i < num_large_objects; i ++) { do_item_unlink(large_items[i].it, UNLINK_NORMAL, large_items[i].key); } do_item_deref(lru_trigger); TASSERT(fsi.large_free_list_sz == large_free_list_sz && fsi.small_free_list_sz == small_free_list_sz); return 0; }
/* * this is a negative test to ensure the proper behavior when we don't have * sufficient resources. in this case, we have sufficient small items on the * LRU, and enough of them have refcount == 0, but all the parent broken chunks * have refcount > 0. */ static int insufficient_available_large_broken_chunks(int verbose) { typedef struct { item* it; char key[KEY_MAX_LENGTH]; uint8_t klen; } all_small_chunks_key_t; size_t num_objects = fsi.large_free_list_sz * SMALL_CHUNKS_PER_LARGE_CHUNK; all_small_chunks_key_t* small_items = malloc(sizeof(all_small_chunks_key_t) * num_objects); item* lru_trigger; size_t max_key_size = SMALL_TITLE_CHUNK_DATA_SZ; size_t min_size_for_large_chunk = ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 1) * sizeof( ((small_body_chunk_t*) 0)->data ) ) + 1; size_t i; char key[KEY_MAX_LENGTH]; size_t klen; size_t large_free_list_sz = fsi.large_free_list_sz, small_free_list_sz = fsi.small_free_list_sz; V_PRINTF(1, " * %s\n", __FUNCTION__); TASSERT(fsi.large_free_list_sz != 0); TASSERT(fsi.small_free_list_sz == 0); for (i = 0; i < num_objects; i ++) { V_PRINTF(2, "\r * allocating object %lu", i); V_FLUSH(2); do { small_items[i].klen = make_random_key(small_items[i].key, max_key_size, true); } while (assoc_find(small_items[i].key, small_items[i].klen)); small_items[i].it = do_item_alloc(small_items[i].key, small_items[i].klen, FLAGS, 0, 0, addr); TASSERT(small_items[i].it); TASSERT(is_item_large_chunk(small_items[i].it) == false); do_item_link(small_items[i].it, small_items[i].key); } V_PRINTF(2, "\n"); TASSERT(fsi.large_free_list_sz == 0 && fsi.small_free_list_sz == 0); V_LPRINTF(2, "alloc before deref\n"); do { klen = make_random_key(key, max_key_size, true); } while (assoc_find(key, klen)); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, min_size_for_large_chunk - klen, addr); TASSERT(lru_trigger == NULL); V_LPRINTF(2, "dereferencing objects\n"); for (i = 0; i < num_objects; i += 2) { do_item_deref(small_items[i].it); } V_LPRINTF(2, "alloc after deref\n"); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, min_size_for_large_chunk - klen, addr); TASSERT(lru_trigger == NULL); V_LPRINTF(2, "ensuring that objects that shouldn't be evicted are still present\n"); for (i = 0; i < num_objects; i ++) { bool should_be_found; /* we free everything we encounter that has no refcount until we hit the * LRU_SEARCH_DEPTH, at which time we cease searching. */ if (i % 2 == 0 && i < (LRU_SEARCH_DEPTH * 2)) { should_be_found = false; } else { should_be_found = true; } TASSERT((assoc_find(small_items[i].key, small_items[i].klen) ? (true) : (false)) == should_be_found); } V_LPRINTF(2, "cleanup objects\n"); for (i = 0; i < num_objects; i ++) { /* we dereference all the odd numbered items */ if ((i % 2) != 0) { do_item_deref(small_items[i].it); } /* we unlink everything that's still in the LRU. */ if (i % 2 == 0 && i < (LRU_SEARCH_DEPTH * 2)) { ; } else { do_item_unlink(small_items[i].it, UNLINK_NORMAL, small_items[i].key); } } TASSERT(fsi.large_free_list_sz == large_free_list_sz && fsi.small_free_list_sz == small_free_list_sz); return 0; }
/* * allocate nearly all memory with small items (all memory - * SMALL_CHUNKS_PER_LARGE_CHUNK - 1). then set it up such that there is only * one item eligible to be freed (i.e., by removing the remaining items from the * LRU. allocate one large object. this will require the migration of one * single chunk item at the LRU head. this covers part of case 1 for the small * item alloc in flat_storage_lru_evict(..). */ static int all_small_items_migrate_small_single_chunk_item_at_lru_head_test(int verbose) { typedef struct { item* it; char key[KEY_MAX_LENGTH]; uint8_t klen; } test_keys_t; size_t num_objects = fsi.large_free_list_sz * SMALL_CHUNKS_PER_LARGE_CHUNK; test_keys_t* items = malloc(sizeof(test_keys_t) * num_objects); item* lru_trigger; size_t max_small_key_size = SMALL_TITLE_CHUNK_DATA_SZ; size_t min_size_for_large_chunk = ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 1) * sizeof( ((small_body_chunk_t*) 0)->data ) ) + 1; size_t i, count; char key[KEY_MAX_LENGTH]; size_t klen; size_t large_free_list_sz = fsi.large_free_list_sz, small_free_list_sz = fsi.small_free_list_sz; V_PRINTF(1, " * %s\n", __FUNCTION__); TASSERT(fsi.large_free_list_sz != 0); TASSERT(fsi.small_free_list_sz == 0); for (i = 0, count = 0; fsi.large_free_list_sz || fsi.small_free_list_sz > SMALL_CHUNKS_PER_LARGE_CHUNK - 1; i ++, count ++) { V_PRINTF(2, "\r * allocating small object %lu", i); V_FLUSH(2); assert(i < num_objects); do { items[i].klen = make_random_key(items[i].key, max_small_key_size, true); } while (assoc_find(items[i].key, items[i].klen)); items[i].it = do_item_alloc(items[i].key, items[i].klen, FLAGS, 0, 0, addr); TASSERT(items[i].it); TASSERT(is_item_large_chunk(items[i].it) == 0); do_item_link(items[i].it, items[i].key); } V_PRINTF(2, "\n"); TASSERT(fsi.large_free_list_sz == 0); TASSERT(fsi.small_free_list_sz == SMALL_CHUNKS_PER_LARGE_CHUNK - 1); // remove all but one item from the LRU. and release our reference to the // item we don't remove from the LRU. for (i = 0; i < count - 1; i ++) { do_item_unlink(items[i].it, UNLINK_NORMAL, items[i].key); } do_item_deref(items[count - 1].it); TASSERT(fsi.lru_head == items[count - 1].it); TASSERT(fsi.large_free_list_sz == 0); TASSERT(fsi.small_free_list_sz == SMALL_CHUNKS_PER_LARGE_CHUNK - 1); V_LPRINTF(2, "alloc\n"); do { klen = make_random_key(key, max_small_key_size, true); } while (assoc_find(key, klen)); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, min_size_for_large_chunk - klen, addr); TASSERT(lru_trigger != NULL); V_LPRINTF(2, "search for evicted object\n"); TASSERT(assoc_find(items[count - 1].key, items[count - 1].klen) == NULL); V_LPRINTF(2, "cleanup objects\n"); for (i = 0; i < count - 1; i ++) { do_item_deref(items[i].it); } do_item_deref(lru_trigger); TASSERT(fsi.large_free_list_sz == large_free_list_sz && fsi.small_free_list_sz == small_free_list_sz); return 0; }
/* * allocate all memory with small items. allocate one large object that can be * covered by the release of small items, but also requires the migration of * single chunk items. this covers part of case 1 for the large item alloc in * flat_storage_lru_evict(..). */ static int all_small_items_migrate_small_single_chunk_items_test(int verbose) { typedef struct { item* it; char key[KEY_MAX_LENGTH]; uint8_t klen; } test_keys_t; size_t num_objects = fsi.large_free_list_sz * SMALL_CHUNKS_PER_LARGE_CHUNK; test_keys_t* items = malloc(sizeof(test_keys_t) * num_objects); item* lru_trigger; size_t max_small_key_size = SMALL_TITLE_CHUNK_DATA_SZ; size_t min_size_for_large_chunk = ( sizeof( ((small_title_chunk_t*) 0)->data ) ) + ( (SMALL_CHUNKS_PER_LARGE_CHUNK - 1) * sizeof( ((small_body_chunk_t*) 0)->data ) ) + 1; size_t i; char key[KEY_MAX_LENGTH]; size_t klen; size_t large_free_list_sz = fsi.large_free_list_sz, small_free_list_sz = fsi.small_free_list_sz; V_PRINTF(1, " * %s\n", __FUNCTION__); TASSERT(fsi.large_free_list_sz != 0); TASSERT(fsi.small_free_list_sz == 0); for (i = 0; i < num_objects; i ++) { V_PRINTF(2, "\r * allocating small object %lu", i); V_FLUSH(2); do { items[i].klen = make_random_key(items[i].key, max_small_key_size, true); } while (assoc_find(items[i].key, items[i].klen)); items[i].it = do_item_alloc(items[i].key, items[i].klen, FLAGS, 0, 0, addr); TASSERT(items[i].it); TASSERT(is_item_large_chunk(items[i].it) == 0); do_item_link(items[i].it, items[i].key); } V_PRINTF(2, "\n"); TASSERT(fsi.large_free_list_sz == 0 && fsi.small_free_list_sz == 0); /* access items we don't want to move. */ current_time += ITEM_UPDATE_INTERVAL + 1; /* touch every other item. the ones that are not touched in (0, * SMALL_CHUNKS_PER_LARGE_CHUNK * 2) will be evicted. */ for (i = 0; i < SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i += 2) { do_item_update(items[i].it); } /* touch remaining items */ for (i = SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i < num_objects; i ++) { do_item_update(items[i].it); } V_LPRINTF(2, "dereferencing objects\n"); for (i = 0; i < num_objects; i ++) { do_item_deref(items[i].it); } V_LPRINTF(2, "alloc after deref\n"); do { klen = make_random_key(key, max_small_key_size, true); } while (assoc_find(key, klen)); lru_trigger = do_item_alloc(key, klen, FLAGS, 0, min_size_for_large_chunk - klen, addr); TASSERT(lru_trigger != NULL); V_LPRINTF(2, "search for evicted object\n"); for (i = 1; i < SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i += 2) { TASSERT(assoc_find(items[i].key, items[i].klen) == NULL); } V_LPRINTF(2, "ensuring that objects that shouldn't be evicted are still present\n"); for (i = 0; i < SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i += 2) { /* these may have been moved. */ TASSERT((items[i].it = assoc_find(items[i].key, items[i].klen))); } for (i = SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i < num_objects; i ++) { TASSERT(assoc_find(items[i].key, items[i].klen)); } V_LPRINTF(2, "cleanup objects\n"); for (i = 0; i < SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i += 2) { do_item_unlink(items[i].it, UNLINK_NORMAL, items[i].key); } for (i = SMALL_CHUNKS_PER_LARGE_CHUNK * 2; i < num_objects; i ++) { do_item_unlink(items[i].it, UNLINK_NORMAL, items[i].key); } do_item_deref(lru_trigger); TASSERT(fsi.large_free_list_sz == large_free_list_sz && fsi.small_free_list_sz == small_free_list_sz); return 0; }
/** * TXイベント * @param u8CbId * @param bStatus */ static void cbAppToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) { // 送信完了 V_PRINTF(LB"! Tx Cmp = %d", bStatus); ToCoNet_Event_Process(E_ORDER_KICK, 0, vProcessEvCore); }