/**************************************************************************** * * 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); } }
/** @ingroup MBUSA * 自身のシリアル番号を出力する(起動時メッセージにも利用) * @param pSer 出力先ストリーム */ void vModbOut_MySerial(tsFILE *pSer) { uint8 *q = au8SerOutBuff; S_OCTET(VERSION_MAIN); S_OCTET(VERSION_SUB); S_OCTET(VERSION_VAR); S_BE_DWORD(ToCoNet_u32GetSerial()); SerCmdAscii_Output_AdrCmd(pSer, SERCMD_ADDR_FR_MODULE, SERCMD_ID_INFORM_MODULE_ADDRESS, au8SerOutBuff, q - au8SerOutBuff); }
/**************************************************************************** * * NAME: AppColdStart * * DESCRIPTION: * * RETURNS: * ****************************************************************************/ void cbAppColdStart(bool_t bAfterAhiInit) { if (!bAfterAhiInit) { // before AHI initialization (very first of code) // Module Registration ToCoNet_REG_MOD_ALL(); } else { // clear application context memset(&sAppData, 0x00, sizeof(sAppData)); // SPRINTF SPRINTF_vInit128(); // Configuration // フラッシュメモリからの読み出し // フラッシュからの読み込みが失敗した場合、ID=15 で設定する sAppData.bFlashLoaded = Config_bLoad(&sAppData.sFlash); // ToCoNet configuration sToCoNet_AppContext.u32AppId = sAppData.sFlash.sData.u32appid; sToCoNet_AppContext.u8Channel = sAppData.sFlash.sData.u8ch; sToCoNet_AppContext.u32ChMask = sAppData.sFlash.sData.u32chmask; sToCoNet_AppContext.u8TxMacRetry = 1; sToCoNet_AppContext.bRxOnIdle = TRUE; // event machine ToCoNet_Event_Register_State_Machine(vProcessEvCore); // main state machine // Other Hardware vSerialInit(); ToCoNet_vDebugInit(&sSerStream); ToCoNet_vDebugLevel(TOCONET_DEBUG_LEVEL); vInitHardware(FALSE); Interactive_vInit(); // START UP MESSAGE vfPrintf(&sSerStream, "\r\n*** ToCoTemp Parent %d.%02d-%d ***", VERSION_MAIN, VERSION_SUB, VERSION_VAR); vfPrintf(&sSerStream, LB "* App ID:%08x Long Addr:%08x Short Addr %04x", sToCoNet_AppContext.u32AppId, ToCoNet_u32GetSerial(), sToCoNet_AppContext.u16ShortAddress); } }
/**************************************************************************** * * NAME: AppColdStart * * DESCRIPTION: * * RETURNS: * ****************************************************************************/ PUBLIC void cbAppColdStart(bool_t bAfterAhiInit) { if (!bAfterAhiInit) { // before AHI initialization (very first of code) // Module Registration ToCoNet_REG_MOD_ALL(); } else { // clear application context memset(&sAppData, 0x00, sizeof(sAppData)); memset(&sSerCmd, 0x00, sizeof(sSerCmd)); // SPRINTF SPRINTF_vInit128(); // configure network] sToCoNet_AppContext.u32AppId = APP_ID; sToCoNet_AppContext.u8Channel = CHANNEL; sToCoNet_AppContext.u32ChMask = CHMASK; sToCoNet_AppContext.u8TxMacRetry = 1; sToCoNet_AppContext.bRxOnIdle = TRUE; // version info sAppData.u32ToCoNetVersion = ToCoNet_u32GetVersion(); // event machine ToCoNet_Event_Register_State_Machine(vProcessEvCore); // main state machine // Other Hardware vSerialInit(); ToCoNet_vDebugInit(&sSerStream); ToCoNet_vDebugLevel(TOCONET_DEBUG_LEVEL); vInitHardware(FALSE); // START UP MESSAGE vfPrintf(&sSerStream, "\r\n\r\n*** " APP_NAME " %d.%02d-%d ***", VERSION_MAIN, VERSION_SUB, VERSION_VAR); vfPrintf(&sSerStream, LB "* App ID:%08x Long Addr:%08x Short Addr %04x", sToCoNet_AppContext.u32AppId, ToCoNet_u32GetSerial(), sToCoNet_AppContext.u16ShortAddress); } }
/** @ingroup FLASH * フラッシュ設定構造体をデフォルトに巻き戻します。 * - ここでシステムのデフォルト値を決めています。 * * @param p 構造体へのアドレス */ void Config_vSetDefaults(tsFlashApp *p) { p->u32appid = ToCoNet_u32GetSerial(); p->u8ch = ((p->u32appid - 1) & 0xF) + 11; // 1..0x10 => 11..26 p->u32chmask = (1UL << p->u8ch); p->u8pow = 3; p->u8role = E_APPCONF_ROLE_MAC_NODE; p->u8layer = 1; p->u16SleepDur_ms = MODE4_SLEEP_DUR_ms; p->u16SleepDur_s = (MODE7_SLEEP_DUR_ms / 1000); p->u8Fps = 32; p->u32PWM_Hz = 1000; p->u32baud_safe = UART_BAUD_SAFE; p->u8parity = 0; // none #ifdef USE_TOCOSTICK p->u32Opt = E_APPCONF_OPT_DISABLE_ADC; // ToCoStick では AI 入力は未接続なので無効化しておく p->u8id = 121; // ToCoStick では親機をデフォルトにする #elif BICYCLEFINDER_MASTER p->u8id = 127; p->u32Opt = E_APPCONF_OPT_DISABLE_ADC|E_APPCONF_OPT_NO_ADC_BASED_TRANSMIT|E_APPCONF_OPT_ON_PRESS_TRANSMIT; #elif BICYCLEFINDER_SLAVE p->u8id = 124; p->u32Opt = (E_APPCONF_OPT_PWM_INIT_LOW | E_APPCONF_OPT_LOUDNESS_EN1 | E_APPCONF_OPT_LOUDNESS_EN2 | E_APPCONF_OPT_DISABLE_ADC); #else p->u8id = 0; p->u32Opt = E_APPCONF_OPT_DISABLE_ADC; // DISABLE_ADC #endif #ifdef BICYCLEFINDER_SLAVE p->u32Opt2 = 0x00000030; // DO1-2のpull up停止 #else p->u32Opt2 = 0x00000000; #endif p->u8MML_idx = 0; }
/** @ingroup MASTER * I2C のコマンドを実行して、応答を返します。 * 無線経由ので要求の場合は、応答は送信元へ無線パケットで戻されます。 * アドレスが0xDBの場合は、要求は自身のモジュールで実行された上 UART に応答します。 * * - 入力フォーマット * - OCTET: ネットワークアドレス(宛先,0xDBは自身のモジュールで実行してUARTに出力) * - OCTET: 0x88 * - OCTET: 要求番号 * - OCTET: コマンド (0x1: Write, 0x2: Read, 0x3: Write and Increment, 0x4: Write and Read) * - OCTET: I2Cアドレス * - OCTET: I2Cコマンド * - OCTET: データサイズ (無い時は 0) * - OCTET[N]: データ (データサイズが0のときは、本フィールドは無し) * * - 出力フォーマット * - OCTET: ネットワークアドレス * - OCTET: 0x89 * - OCTET: 要求番号、入力フォーマットの値がコピーされる * - OCTET: コマンド (0x1: Write, 0x2: Read) * - OCTET: 0:FAIL, 1:SUCCESS * - OCTET: データサイズ (無い時は 0) * - OCTET[N]: データ (データサイズが0のときは、本フィールドは無し) * * @param p 入力書式のバイト列 * @param u16len バイト列長 * @param u8AddrSrc 要求元のネットワークアドレス */ void vProcessI2CCommand(uint8 *p, uint16 u16len, uint8 u8AddrSrc) { //uint8 *p_end = p + u16len; uint8 au8OutBuf[256 + 32]; uint8 *q = au8OutBuf; bool_t bOk = TRUE; uint8 n; static volatile uint16 x; // 入力データの解釈 uint8 u8Addr = G_OCTET(); (void) u8Addr; uint8 u8Command = G_OCTET(); if (u8Command != SERCMD_ID_I2C_COMMAND) { return; } uint8 u8ReqNum = G_OCTET(); uint8 u8I2C_Oper = G_OCTET(); uint8 u8I2C_Addr = G_OCTET(); uint8 u8I2C_Cmd = G_OCTET(); uint8 u8DataSize = G_OCTET(); uint8 *pu8data = p; //uint8 *pu8data_end = p + u8DataSize; #if 0 if (pu8data_end != p_end) { DBGOUT(1, "I2CCMD: incorrect data."LB); return; } #endif // 出力用のバッファを用意しておく S_OCTET(sAppData.u8AppLogicalId); S_OCTET(SERCMD_ID_I2C_COMMAND_RESP); S_OCTET(u8ReqNum); S_OCTET(u8I2C_Oper); //ここで q[0] 成功失敗フラグ, q[1] データサイズ, q[2]... データ q[0] = FALSE; q[1] = 0; DBGOUT(1, "I2CCMD: req#=%d Oper=%d Addr=%02x Cmd=%02x Siz=%d"LB, u8ReqNum, u8I2C_Oper, u8I2C_Addr, u8I2C_Cmd, u8DataSize); switch (u8I2C_Oper) { case 1: bOk &= bSMBusWrite(u8I2C_Addr, u8I2C_Cmd, u8DataSize, u8DataSize == 0 ? NULL : pu8data); break; case 2: if (u8DataSize > 0) { bOk &= bSMBusSequentialRead(u8I2C_Addr, u8DataSize, &(q[2])); if (bOk) q[1] = u8DataSize; } else { bOk = FALSE; } break; case 3: for (n = 0; n < u8DataSize; n++) { bOk &= bSMBusWrite(u8I2C_Addr, u8I2C_Cmd + n, 1, &pu8data[n]); for (x = 0; x < 16000; x++) ; //wait (e.g. for memory device) } break; case 4: if (u8DataSize > 0) { bOk &= bSMBusWrite(u8I2C_Addr, u8I2C_Cmd, 0, NULL ); if (bOk) bOk &= bSMBusSequentialRead(u8I2C_Addr, u8DataSize, &(q[2])); if (bOk) q[1] = u8DataSize; } else { bOk = FALSE; } break; #ifdef USE_I2C_ACM1620 case 0x21: // ACM1620 bDraw2LinesLcd_ACM1602((const char *) pu8data, (const char *) (pu8data + 16)); break; #endif #ifdef USE_I2C_AQM0802A case 0x22: // ACM1620 bDraw2LinesLcd_AQM0802A((const char *) pu8data, (const char *) (pu8data + 8)); break; #endif default: DBGOUT(1, "I2CCMD: unknown operation(%d)."LB, u8I2C_Oper); return; } q[0] = bOk; // 成功失敗フラグを書き込む q = q + 2 + q[1]; // ポインタ q を進める(データ末尾+1) if (u8AddrSrc == SERCMD_ADDR_TO_MODULE) { SerCmdAscii_Output_AdrCmd(&sSerStream, u8AddrSrc, au8OutBuf[1], au8OutBuf + 2, q - au8OutBuf - 2); } else { i16TransmitSerMsg(au8OutBuf, q - au8OutBuf, ToCoNet_u32GetSerial(), sAppData.u8AppLogicalId, u8AddrSrc, FALSE, sAppData.u8UartReqNum++); } }
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); // スリープ状態へ遷移 } }
/** * 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); // スリープ状態へ遷移 } }
/**************************************************************************** * * NAME: vHandleSerialInput * * DESCRIPTION: * * PARAMETERS: Name RW Usage * * RETURNS: * * NOTES: ****************************************************************************/ PRIVATE void vHandleSerialInput() { // handle UART command while (!SERIAL_bRxQueueEmpty(sSerPort.u8SerialPort)) { int16 i16Char; i16Char = SERIAL_i16RxChar(sSerPort.u8SerialPort); // process if (i16Char >=0 && i16Char <= 0xFF) { uint8 u8res = u8ParseSerCmd(&sSerCmd, (uint8)i16Char); if (u8res == E_SERCMD_VERBOSE) { vfPrintf(&sSerStream, "\n\rVERBOSE MODE = %s", bSerCmd_VerboseMode ? "ON" : "OFF"); continue; } if (!bSerCmd_VerboseMode) continue; switch (i16Char) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': sAppData.sFlash.sData.u8Layer = i16Char - '0'; if (bFlash_Write(&sAppData.sFlash, FLASH_SECTOR_NUMBER - 1, 0)) { V_PRINTF( LB "Flash Saved (Router Layer #%d)... RESETTING", sAppData.sFlash.sData.u8Layer); vWait(100000); vAHI_SwReset(); } else { V_PRINTF( LB "Failed to save flash..."); } break; case 'i': // info _C { tsToCoNet_NwkLyTr_Context *pc = (tsToCoNet_NwkLyTr_Context *)(sAppData.pContextNwk); V_PRINTF( LB "Info: la=%d ty=%d ro=%02x st=%02x", pc->sInfo.u8Layer, pc->sInfo.u8NwkTypeId, pc->sInfo.u8Role, pc->sInfo.u8State); V_PRINTF( LB "Parent: %08x", pc->u32AddrHigherLayer); V_PRINTF( LB "LostParent: %d", pc->u8Ct_LostParent); V_PRINTF( LB "SecRescan: %d, SecRelocate: %d", pc->u8Ct_Second_To_Rescan, pc->u8Ct_Second_To_Relocate); } break; case '>': sToCoNet_AppContext.u8Channel++; if (sToCoNet_AppContext.u8Channel > 25) sToCoNet_AppContext.u8Channel = 0; ToCoNet_vRfConfig(); V_PRINTF( LB"channel set to %d.", sToCoNet_AppContext.u8Channel); break; case '<': sToCoNet_AppContext.u8Channel--; if (sToCoNet_AppContext.u8Channel < 11) sToCoNet_AppContext.u8Channel = 25; ToCoNet_vRfConfig(); V_PRINTF( LB"channel set to %d.", sToCoNet_AppContext.u8Channel); break; case 't': SPRINTF_vRewind(); vfPrintf(SPRINTF_Stream, "TEST FROM ROUTER(#%08X)", ToCoNet_u32GetSerial()); bTransmitToParent(sAppData.pContextNwk, SPRINTF_pu8GetBuff(), SPRINTF_u16Length()); break; case 'd': case 'D': _C { static uint8 u8DgbLvl; u8DgbLvl++; if(u8DgbLvl > 10) u8DgbLvl = 0; ToCoNet_vDebugLevel(u8DgbLvl); V_PRINTF( LB"set NwkCode debug level to %d.", u8DgbLvl); } break; default: break; } } }
/** * 初期化メッセージ */ void vSerInitMessage() { V_PRINTF(LB "*** " APP_NAME " (Router) %d.%02d-%d ***", VERSION_MAIN, VERSION_SUB, VERSION_VAR); V_PRINTF(LB "* App ID:%08x Long Addr:%08x Short Addr %04x LID %02d", sToCoNet_AppContext.u32AppId, ToCoNet_u32GetSerial(), sToCoNet_AppContext.u16ShortAddress, sAppData.sFlash.sData.u8id); }
/**************************************************************************** * * NAME: cbvMcRxHandler * * DESCRIPTION: * * RETURNS: * ****************************************************************************/ PUBLIC void cbToCoNet_vRxEvent(tsRxDataApp *pRx) { int i; // print coming payload V_PRINTF( LB "[PKT Ad:%04x,Ln:%03d,Seq:%03d,Lq:%03d,Tms:%05d %s\"", pRx->u32SrcAddr, pRx->u8Len, // Actual payload byte: the network layer uses additional 4 bytes. pRx->u8Seq, pRx->u8Lqi, pRx->u32Tick & 0xFFFF, pRx->bSecurePkt ? "Enc " : ""); 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 (IS_APPCONF_OPT_SECURE()) { if (!pRx->bSecurePkt) { V_PRINTF( ".. skipped plain packet."); return; } } // 直接受信したパケットを上位へ転送する // // 直接親機宛(TOCONET_NWK_ADDR_PARENT指定で送信)に向けたパケットはここでは処理されない。 // 本処理はアドレス指定がTOCONET_NWK_ADDR_NEIGHBOUR_ABOVEの場合で、一端中継機が受け取り // その中継機のアドレス、受信時のLQIを含めて親機に伝達する方式である。 if (pRx->auData[0] == 'T') { tsTxDataApp sTx; memset(&sTx, 0, sizeof(sTx)); uint8 *q = sTx.auData; S_OCTET('R'); // 1バイト目に中継機フラグを立てる S_BE_DWORD(pRx->u32SrcAddr); // 子機のアドレスを S_OCTET(pRx->u8Lqi); // 受信したLQI を保存する memcpy(sTx.auData + 6, pRx->auData + 1, pRx->u8Len - 1); // 先頭の1バイトを除いて5バイト先にコピーする q += pRx->u8Len - 1; sTx.u8Len = q - sTx.auData; 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; // 送信開始の遅延を大きめに設定する if (IS_APPCONF_OPT_SECURE()) { sTx.bSecurePacket = TRUE; } ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx); } }
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; } }
/* パケットを送信する状態 */ 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); } }