/* * Copyright (C) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "state_machine.h" #include "ILog.h" #undef LOG_TAG #define LOG_TAG "OHWIFI_STATE_MACHINE" // namespace OHOS { // namespace Wifi { static const int SM_INIT_CMD = -2; StateMachine::StateMachine(const std::string &name) : pStateMachineHandler(nullptr), mStateName(name) {} StateMachine::~StateMachine() { LogInfo("StateMachine::~StateMachine\n"); if (pStateMachineHandler != nullptr) { delete pStateMachineHandler; pStateMachineHandler = nullptr; } } bool StateMachine::InitialStateMachine() { pStateMachineHandler = new (std::nothrow) StateMachineHandler(this); if (pStateMachineHandler == nullptr) { LogError("pStateMachineHandler alloc failed.\n"); return false; } if (!pStateMachineHandler->InitialSmHandler()) { LogError("InitialStateMachineHandler failed.\n"); return false; } return true; } void StateMachine::StartStateMachine() { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->BuildTreeComplete(); return; } void StateMachine::SetHandler(StateMachineHandler *handler) { pStateMachineHandler = handler; } void StateMachine::NotExecutedMessage(const InternalMessage *msg) { if (msg == nullptr) { return; } LogWarning("msg not handled msg:%d\n", msg->GetMessageName()); } void StateMachine::StatePlus(State *state, State *upper) { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->StatePlus(state, upper); } void StateMachine::StateDelete(State *state) { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->StateDelete(state); } void StateMachine::SetTopState(State *firstState) { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->SetTopState(firstState); } void StateMachine::SwitchState(State *targetState) { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->SwitchState(targetState); } void StateMachine::DelayMessage(const InternalMessage *msg) { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->DelayMessage(msg); } void StateMachine::DelayMessage(VStateMachineData *msg) { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->DelayMessage((InternalMessage *)msg); } void StateMachine::StopHandlerThread() { if (pStateMachineHandler == nullptr) { LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); return; } pStateMachineHandler->StopHandlerThread(); } InternalMessage *StateMachine::CreateMessage() { return MessageManage::GetInstance().CreateMessage(); } InternalMessage *StateMachine::CreateMessage(const InternalMessage *orig) { if (orig == nullptr) { return nullptr; } return MessageManage::GetInstance().CreateMessage(orig); } InternalMessage *StateMachine::CreateMessage(int msgName) { return MessageManage::GetInstance().CreateMessage(msgName); } InternalMessage *StateMachine::CreateMessage(int msgName, int param1) { return MessageManage::GetInstance().CreateMessage(msgName, param1, 0); } InternalMessage *StateMachine::CreateMessage(int msgName, int param1, int param2) { return MessageManage::GetInstance().CreateMessage(msgName, param1, param2); } InternalMessage *StateMachine::CreateMessage(int msgName, const std::shared_ptr &messageObj) { return MessageManage::GetInstance().CreateMessage(msgName, messageObj); } InternalMessage *StateMachine::CreateMessage(int msgName, int param1, int param2, const std::shared_ptr &messageObj) { return MessageManage::GetInstance().CreateMessage(msgName, param1, param2, messageObj); } void StateMachine::SendMessage(int msgName) { pStateMachineHandler->SendMessage(CreateMessage(msgName)); return; } void StateMachine::SendMessage(int msgName, int param1) { pStateMachineHandler->SendMessage(CreateMessage(msgName, param1)); return; } void StateMachine::SendMessage(int msgName, int param1, int param2) { pStateMachineHandler->SendMessage(CreateMessage(msgName, param1, param2)); return; } void StateMachine::SendMessage(InternalMessage *msg) { if (msg == nullptr) { return; } pStateMachineHandler->SendMessage(msg); return; } void StateMachine::SendMessage(int msgName, const std::shared_ptr &messageObj) { pStateMachineHandler->SendMessage(CreateMessage(msgName, messageObj)); return; } void StateMachine::SendMessage(int msgName, int param1, int param2, const std::shared_ptr &messageObj) { pStateMachineHandler->SendMessage(CreateMessage(msgName, param1, param2, messageObj)); return; } void StateMachine::MessageExecutedLater(int msgName, int64_t delayTimeMs) { pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName), delayTimeMs); return; } void StateMachine::MessageExecutedLater(int msgName, int param1, int64_t delayTimeMs) { pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, param1), delayTimeMs); return; } void StateMachine::MessageExecutedLater(int msgName, int param1, int param2, int64_t delayTimeMs) { pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, param1, param2), delayTimeMs); return; } void StateMachine::MessageExecutedLater(InternalMessage *msg, int64_t delayTimeMs) { pStateMachineHandler->MessageExecutedLater(msg, delayTimeMs); return; } void StateMachine::MessageExecutedLater(int msgName, const std::shared_ptr &messageObj, int64_t delayTimeMs) { pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, messageObj), delayTimeMs); return; } void StateMachine::MessageExecutedLater( int msgName, int param1, int param2, const std::shared_ptr &messageObj, int64_t delayTimeMs) { pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, param1, param2, messageObj), delayTimeMs); return; } void StateMachine::StartTimer(int timerName, int64_t interval) { // LogInfo("Enter StateMachine::StartTimer, timerName is %d, interval is %d\n", timerName, interval); MessageExecutedLater(timerName, interval); return; } void StateMachine::StopTimer(int timerName) { // LogInfo("Enter StateMachine::StopTimer, timerName is %d.\n", timerName); pStateMachineHandler->DeleteMessageFromQueue(timerName); return; } StateMachineHandler::StateMachineHandler(StateMachine *pStateMgr) { mStateInfoMap.clear(); mStateVector.clear(); mStateVectorTopIndex = -1; mSequenceStateVector.clear(); mSequenceStateVectorCount = 0; mDelayedMessages.clear(); pStateMachine = pStateMgr; pFirstState = nullptr; pTargetState = nullptr; mQuitFlag = false; mBuildCompleteFlag = false; mSwitchingStateFlag = false; pCurrentMsg = nullptr; } StateMachineHandler::~StateMachineHandler() { LogInfo("StateMachineHandler::~StateMachineHandler\n"); StopHandlerThread(); ReleaseDelayedMessages(); ClearWhenQuit(); return; } bool StateMachineHandler::InitialSmHandler() { if (!InitialHandler()) { return false; } return true; } StateInfo *StateMachineHandler::StatePlus(State *state, State *upper) { LogInfo("Enter StateMachineHandler::StatePlus function.\n"); StateInfo *upperStateInfo = nullptr; StateInfoMap::iterator it = mStateInfoMap.begin(); if (upper != nullptr) { it = mStateInfoMap.find(upper->GetStateName()); if (it != mStateInfoMap.end()) { upperStateInfo = it->second; } if (upperStateInfo == nullptr) { LogInfo("upperStateInfo is null, add upper first. upper->GetStateName():%s\n", upper->GetStateName().c_str()); /* Recursively add our upper as it's not been added yet. */ StatePlus(upper, nullptr); } else { LogInfo("upperStateInfo is not null, go on.\n"); } } StateInfo *stateInfo = nullptr; it = mStateInfoMap.find(state->GetStateName()); if (it != mStateInfoMap.end()) { stateInfo = it->second; } if (stateInfo == nullptr) { stateInfo = new (std::nothrow) StateInfo(); if (stateInfo == nullptr) { LogError("failed to new StateInfo!\n"); return nullptr; } mStateInfoMap.insert(StateInfoMap::value_type(state->GetStateName(), stateInfo)); } /* Validate that we aren't adding the same state in two different hierarchies. */ if (stateInfo->upperStateInfo != nullptr && stateInfo->upperStateInfo != upperStateInfo) { LogError("The same state cannot be added to two different hierarchies!\n"); } stateInfo->state = state; stateInfo->upperStateInfo = upperStateInfo; stateInfo->active = false; LogInfo("successfully added a new state!\n"); return stateInfo; } void StateMachineHandler::StateDelete(State *state) { StateInfoMap::iterator it = mStateInfoMap.find(state->GetStateName()); StateInfo *stateInfo = nullptr; if (it != mStateInfoMap.end()) { stateInfo = it->second; } if (stateInfo == nullptr || stateInfo->active) { return; } it = mStateInfoMap.begin(); while (it != mStateInfoMap.end()) { if (it->second->upperStateInfo == stateInfo) { return; } ++it; } it = mStateInfoMap.find(state->GetStateName()); if (it != mStateInfoMap.end()) { delete it->second; it->second = nullptr; mStateInfoMap.erase(it); } } void StateMachineHandler::SetTopState(State *firstState) { pFirstState = firstState; } void StateMachineHandler::BuildTreeComplete() { /* Determines the maximum depth of the state hierarchy. */ int maxDepth = 0; StateInfoMap::iterator it = mStateInfoMap.begin(); while (it != mStateInfoMap.end()) { int depth = 0; StateInfo *tempStateInfo = it->second; while (tempStateInfo != nullptr) { depth++; tempStateInfo = tempStateInfo->upperStateInfo; } if (maxDepth < depth) { maxDepth = depth; } ++it; } LogInfo("StateMachineHandler::BuildTreeComplete, maxDepth:%d\n", maxDepth); mStateVector.resize(maxDepth); mSequenceStateVector.resize(maxDepth); BuildStateInitVector(); MessageExecutedAtTime(pStateMachine->CreateMessage(SM_INIT_CMD), 0); return; } void StateMachineHandler::BuildStateInitVector() { LogInfo("StateMachineHandler::BuildStateInitVector\n"); if (pFirstState == nullptr) { LogError("StateMachineHandler::BuildStateInitVector please set initial state first!\n"); return; } StateInfoMap::iterator it = mStateInfoMap.find(pFirstState->GetStateName()); StateInfo *startStateInfo = nullptr; if (it != mStateInfoMap.end()) { startStateInfo = it->second; } for (mSequenceStateVectorCount = 0; startStateInfo != nullptr; mSequenceStateVectorCount++) { mSequenceStateVector[mSequenceStateVectorCount] = startStateInfo; startStateInfo = startStateInfo->upperStateInfo; } /* Clearing the StateVector. */ mStateVectorTopIndex = -1; MoveSequenceToStateVector(); } StateInfo *StateMachineHandler::BuildSequenceStateVector(State *targetState) { mSequenceStateVectorCount = 0; StateInfoMap::iterator it = mStateInfoMap.find(targetState->GetStateName()); StateInfo *curStateInfo = nullptr; if (it != mStateInfoMap.end()) { curStateInfo = it->second; } if (curStateInfo == nullptr) { return nullptr; } do { mSequenceStateVector[mSequenceStateVectorCount++] = curStateInfo; curStateInfo = curStateInfo->upperStateInfo; } while ((curStateInfo != nullptr) && (!curStateInfo->active)); return curStateInfo; } void StateMachineHandler::PlaceDelayedMsgQueueTop() { // LogInfo("Enter StateMachineHandler::PlaceDelayedMsgQueueTop.\n"); for (int i = mDelayedMessages.size() - 1; i >= 0; i--) { InternalMessage *curMsg = mDelayedMessages[i]; if (curMsg == nullptr) { LogError("StateMachineHandler::PlaceDelayedMsgQueueTop: curMsg is null.\n"); continue; } PlaceMessageTopOfQueue(curMsg); } mDelayedMessages.clear(); return; } void StateMachineHandler::ReleaseDelayedMessages() { for (int i = mDelayedMessages.size() - 1; i >= 0; i--) { InternalMessage *curMsg = mDelayedMessages[i]; if (curMsg != nullptr) { delete curMsg; curMsg = nullptr; } } mDelayedMessages.clear(); return; } int StateMachineHandler::MoveSequenceToStateVector() { // LogInfo("StateMachineHandler::MoveSequenceToStateVector mSequenceStateVectorCount:%d\n", // mSequenceStateVectorCount); int newIndex = mStateVectorTopIndex + 1; int i = mSequenceStateVectorCount - 1; int j = newIndex; while (i >= 0) { mStateVector[j] = mSequenceStateVector[i]; j += 1; i -= 1; } mStateVectorTopIndex = j - 1; return newIndex; } void StateMachineHandler::SwitchState(State *targetState) { pTargetState = static_cast(targetState); } void StateMachineHandler::ClearWhenQuit() { pStateMachine->SetHandler(nullptr); pStateMachine = nullptr; pCurrentMsg = nullptr; mStateVector.clear(); mSequenceStateVector.clear(); mDelayedMessages.clear(); pFirstState = nullptr; pTargetState = nullptr; mQuitFlag = true; StateInfoMap::iterator it = mStateInfoMap.begin(); while (it != mStateInfoMap.end()) { delete it->second; it->second = nullptr; it = mStateInfoMap.erase(it); } mStateInfoMap.clear(); } void StateMachineHandler::PerformSwitchState(State *msgProcessedState, InternalMessage *msg) { if (msgProcessedState == nullptr || msg == nullptr) { // LogError("poniter is null.\n"); } State *targetState = pTargetState; if (targetState != nullptr) { // LogInfo("StateMachineHandler::PerformSwitchState targetState name is: %s\n", // targetState->GetStateName().c_str()); while (true) { StateInfo *commonStateInfo = BuildSequenceStateVector(targetState); mSwitchingStateFlag = true; CallTreeStateExits(commonStateInfo); int stateListEnteringIndex = MoveSequenceToStateVector(); CallTreeStateEnters(stateListEnteringIndex); PlaceDelayedMsgQueueTop(); if (targetState != pTargetState) { targetState = pTargetState; } else { break; } } pTargetState = nullptr; } return; } void StateMachineHandler::ExecuteMessage(InternalMessage *msg) { if (msg == nullptr) { return; } if (!mQuitFlag) { if (pStateMachine != nullptr && msg->GetMessageName() != SM_INIT_CMD) { } pCurrentMsg = msg; State *msgProcessedState = nullptr; if (mBuildCompleteFlag) { // LogInfo("StateMachineHandler::ExecuteMessage ExecuteTreeStateMsg!\n"); msgProcessedState = ExecuteTreeStateMsg(msg); } else if (!mBuildCompleteFlag && msg->GetMessageName() == SM_INIT_CMD) { // LogInfo("StateMachineHandler::ExecuteMessage msg: SM_INIT_CMD\n"); mBuildCompleteFlag = true; CallTreeStateEnters(0); } else { LogError("The start method not called!\n"); } if (pStateMachine != nullptr) { PerformSwitchState(msgProcessedState, msg); } else { LogError("poniter is null.\n"); } if (pStateMachine != nullptr && msg->GetMessageName() != SM_INIT_CMD) { } } return; } void StateMachineHandler::DelayMessage(const InternalMessage *msg) { // LogInfo("Enter StateMachineHandler::DelayMessage.\n"); if (msg == nullptr) { return; } InternalMessage *newMsg = pStateMachine->CreateMessage(msg); if (newMsg == nullptr) { LogError("StateMachineHandler::DelayMessage: newMsg is null.\n"); return; } mDelayedMessages.push_back(newMsg); return; } State *StateMachineHandler::ExecuteTreeStateMsg(InternalMessage *msg) { // LogInfo("StateMachineHandler::ExecuteTreeStateMsg mStateVectorTopIndex:%d\n", mStateVectorTopIndex); if (msg == nullptr) { return nullptr; } StateInfo *curStateInfo = mStateVector[mStateVectorTopIndex]; if (curStateInfo == nullptr) { LogError("StateInfo is null.\n"); return nullptr; } if (curStateInfo->state) { LOGI("State machine: %s execute Cmd:%d\n", curStateInfo->state->GetStateName().c_str(), msg->GetMessageName()); } // TODO: while (curStateInfo->state && (!curStateInfo->state->ExecuteStateMsg((VStateMachineData *)(msg)))) { curStateInfo = curStateInfo->upperStateInfo; if (curStateInfo == nullptr) { pStateMachine->NotExecutedMessage(msg); break; } } return (curStateInfo != nullptr) ? curStateInfo->state : nullptr; } void StateMachineHandler::CallTreeStateExits(StateInfo *commonStateInfo) { while ((mStateVectorTopIndex >= 0) && (mStateVector[mStateVectorTopIndex] != commonStateInfo)) { if (mStateVector[mStateVectorTopIndex] != nullptr) { State *curState = mStateVector[mStateVectorTopIndex]->state; if (curState != nullptr) { curState->GoOutState(); } mStateVector[mStateVectorTopIndex]->active = false; } mStateVectorTopIndex -= 1; } } void StateMachineHandler::CallTreeStateEnters(int index) { for (int i = index; i <= mStateVectorTopIndex; i++) { if (index == mStateVectorTopIndex) { /* Last enter state for transition. */ mSwitchingStateFlag = false; } // LogInfo("StateMachineHandler::CallTreeStateEnters mStateVectorTopIndex:%d, i: %d\n", // mStateVectorTopIndex, // i); if (mStateVector[i] != nullptr && mStateVector[i]->state != nullptr) { mStateVector[i]->state->GoInState(); mStateVector[i]->active = true; } } /* ensure flag set to false if no methods called. */ mSwitchingStateFlag = false; } // } // namespace Wifi // } // namespace OHOS