/** @ingroup MBUSA * フラッシュ設定を出力する。 * ※ 本実装は実験的で、フラッシュのデータ全てに対応していません。 * * @param pSer 出力先ストリーム * @param pConfig 設定構造体 */ void vModbOut_Config(tsFILE *pSer, tsFlashApp *pConfig) { uint8 *q = au8SerOutBuff; S_BE_DWORD(pConfig->u32appid); S_OCTET(pConfig->u8role); S_OCTET(pConfig->u8layer); S_OCTET(pConfig->u8ch); S_BE_DWORD(pConfig->u32chmask); vSerOutput_ModbusAscii(pSer, SERCMD_ADDR_FR_MODULE, SERCMD_ID_INFORM_NETWORK_CONFIG, au8SerOutBuff, q - au8SerOutBuff); }
/** @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); }
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[9]; uint8 *q = au8Data; S_OCTET(sAppData.sSns.u8Batt); S_BE_WORD(sAppData.sSns.u16Adc1); S_BE_WORD(sAppData.sSns.u16Adc2); S_BE_DWORD(sObjTSL2561.u32Result); if ( bSendMessage( au8Data, q-au8Data ) ) { } else { 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: 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); } }