/**************************************************************************** * * NAME: vInitHardware * * DESCRIPTION: * * RETURNS: * ****************************************************************************/ static void vInitHardware(int f_warm_start) { // インタラクティブモードの初期化 Interactive_vInit(); // LED's vPortAsOutput(PORT_KIT_LED1); vPortAsOutput(PORT_KIT_LED2); vPortAsOutput(PORT_KIT_LED3); vPortAsOutput(PORT_KIT_LED4); vPortSetHi(PORT_KIT_LED1); vPortSetHi(PORT_KIT_LED2); vPortSetHi(PORT_KIT_LED3); vPortSetHi(PORT_KIT_LED4); if (!f_warm_start && bPortRead(PORT_CONF2)) { sAppData.bConfigMode = TRUE; } // activate tick timers memset(&sTimerApp, 0, sizeof(sTimerApp)); sTimerApp.u8Device = E_AHI_DEVICE_TIMER0; sTimerApp.u16Hz = 1; sTimerApp.u8PreScale = 10; vTimerConfig(&sTimerApp); vTimerStart(&sTimerApp); }
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); } } }
PUBLIC void cbToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap) { switch (u32DeviceId) { case E_AHI_DEVICE_ANALOGUE: break; case E_AHI_DEVICE_SYSCTRL: break; case E_AHI_DEVICE_TICK_TIMER: // LED BLINK vPortSet_TrueAsLo(PORT_KIT_LED2, u32TickCount_ms & 0x400); // LED ON when receive if (u32TickCount_ms - sAppData.u32LedCt < 300) { vPortSetLo(PORT_KIT_LED1); } else { vPortSetHi(PORT_KIT_LED1); } break; case E_AHI_DEVICE_TIMER0: break; default: break; } }
PRIVATE void vInitHardware(int f_warm_start) { // LED's vPortAsOutput(PORT_KIT_LED1); vPortAsOutput(PORT_KIT_LED2); vPortAsOutput(PORT_KIT_LED3); vPortAsOutput(PORT_KIT_LED4); vPortSetHi(PORT_KIT_LED1); vPortSetHi(PORT_KIT_LED2); vPortSetHi(PORT_KIT_LED3); vPortSetHi(PORT_KIT_LED4); // activate tick timers memset(&sTimerApp, 0, sizeof(sTimerApp)); sTimerApp.u8Device = E_AHI_DEVICE_TIMER0; sTimerApp.u16Hz = 1; sTimerApp.u8PreScale = 10; vTimerConfig(&sTimerApp); vTimerStart(&sTimerApp); }
/** * 始動時の処理 * * @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); // スリープ状態へ遷移 } }
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); } }
/** * スリープへの遷移 * * @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); } }
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); } if( bFirst && sAppData.sFlash.sData.i16param != NORMAL && sAppData.sFlash.sData.i16param != NEKOTTER ){ bFirst = FALSE; V_PRINTF(LB"*** First Sleep..."); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 }else{ bFirst = FALSE; // 初期化後速やかに送信要求 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_ADXL345); // パケット識別子 S_OCTET(sAppData.sSns.u8Batt); S_BE_WORD(sAppData.sSns.u16Adc1); S_BE_WORD(sAppData.sSns.u16Adc2); S_BE_WORD(sObjADXL345.ai16Result[ADXL345_IDX_X]); S_BE_WORD(sObjADXL345.ai16Result[ADXL345_IDX_Y]); S_BE_WORD(sObjADXL345.ai16Result[ADXL345_IDX_Z]); S_OCTET(sAppData.sFlash.sData.i16param & 0x00FF); 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回送信 V_PRINTF( LB"INT = %02X", sObjADXL345.u8Interrupt ); if (IS_APPCONF_OPT_SECURE()) { sTx.bSecurePacket = TRUE; } vPortAsOutput(LED); if (ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx)) { V_PRINTF(LB"TxOk"); #ifdef LITE2525A vPortSetHi(LED); #else vPortSetLo(LED); #endif 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); // スリープ状態へ遷移 } }
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; } }