From 08d451c882ed44808a141729159027b107f4c8b9 Mon Sep 17 00:00:00 2001 From: xiaojiazhu <258828110.@qq.com> Date: Sun, 10 Sep 2023 06:11:12 -0700 Subject: [PATCH] Add state machine module. --- CMakeLists.txt | 9 +- build/global_config.cmake | 1 + middleware/CMakeLists.txt | 2 + middleware/StateMachine/CMakeLists.txt | 47 ++ middleware/StateMachine/README.md | 26 + .../StateMachine/include/IStateMachine.h | 77 ++ middleware/StateMachine/src/IStateMachine.cpp | 42 ++ .../StateMachine/src/OpenHarmony/handler.cpp | 215 ++++++ .../StateMachine/src/OpenHarmony/handler.h | 135 ++++ .../src/OpenHarmony/internal_message.cpp | 332 +++++++++ .../src/OpenHarmony/internal_message.h | 390 ++++++++++ .../src/OpenHarmony/message_queue.cpp | 190 +++++ .../src/OpenHarmony/message_queue.h | 88 +++ .../StateMachine/src/OpenHarmony/state.cpp | 34 + .../StateMachine/src/OpenHarmony/state.h | 26 + .../src/OpenHarmony/state_machine.cpp | 686 ++++++++++++++++++ .../src/OpenHarmony/state_machine.h | 518 +++++++++++++ .../StateMachine/src/StateMachineImpl.cpp | 20 + .../StateMachine/src/StateMachineImpl.h | 25 + .../StateMachine/src/StateMachineMakePtr.cpp | 64 ++ .../StateMachine/src/StateMachineMakePtr.h | 29 + utils/Log/include/ILog.h | 7 + utils/StatusCode/include/StatusCode.h | 1 + 23 files changed, 2956 insertions(+), 8 deletions(-) create mode 100644 middleware/CMakeLists.txt create mode 100644 middleware/StateMachine/CMakeLists.txt create mode 100644 middleware/StateMachine/README.md create mode 100644 middleware/StateMachine/include/IStateMachine.h create mode 100644 middleware/StateMachine/src/IStateMachine.cpp create mode 100644 middleware/StateMachine/src/OpenHarmony/handler.cpp create mode 100644 middleware/StateMachine/src/OpenHarmony/handler.h create mode 100644 middleware/StateMachine/src/OpenHarmony/internal_message.cpp create mode 100644 middleware/StateMachine/src/OpenHarmony/internal_message.h create mode 100644 middleware/StateMachine/src/OpenHarmony/message_queue.cpp create mode 100644 middleware/StateMachine/src/OpenHarmony/message_queue.h create mode 100644 middleware/StateMachine/src/OpenHarmony/state.cpp create mode 100644 middleware/StateMachine/src/OpenHarmony/state.h create mode 100644 middleware/StateMachine/src/OpenHarmony/state_machine.cpp create mode 100644 middleware/StateMachine/src/OpenHarmony/state_machine.h create mode 100644 middleware/StateMachine/src/StateMachineImpl.cpp create mode 100644 middleware/StateMachine/src/StateMachineImpl.h create mode 100644 middleware/StateMachine/src/StateMachineMakePtr.cpp create mode 100644 middleware/StateMachine/src/StateMachineMakePtr.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dc70735..783b4b14 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,14 +42,6 @@ endif() #Add macro definition # add_definitions(-DCONFIG_FILE_PATH=\"${CONFIG_FILE_PATH}\") -# Config message of libs on board -# unset(MAIN_INCLUDE_PATH CACHE) -# set(MAIN_INCLUDE_PATH "" CACHE STRING INTERNAL) -# unset(MAIN_SRC_FILE CACHE) -# set(MAIN_SRC_FILE "" CACHE STRING INTERNAL) -# unset(MAIN_LINK_LIB CACHE) -# set(MAIN_LINK_LIB "" CACHE STRING INTERNAL) - # Config message of main thread unset(MAIN_INCLUDE_PATH CACHE) set(MAIN_INCLUDE_PATH "" CACHE STRING INTERNAL) @@ -85,6 +77,7 @@ endif() # 添加编译目录 # add_subdirectory(application) +add_subdirectory(middleware) add_subdirectory(utils) add_subdirectory(hal) # add_subdirectory(customization) diff --git a/build/global_config.cmake b/build/global_config.cmake index b9c096ff..1841973d 100755 --- a/build/global_config.cmake +++ b/build/global_config.cmake @@ -7,6 +7,7 @@ set(TEST_OUTPUT_PATH "${PLATFORM_PATH}/out/test") set(PROJECT_ROOT_PATH "${PLATFORM_PATH}") set(APPLICATION_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/application") +set(MIDDLEWARE_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/middleware") set(UTILS_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/utils") set(HAL_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/hal") set(TEST_SOURCE_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/test") diff --git a/middleware/CMakeLists.txt b/middleware/CMakeLists.txt new file mode 100644 index 00000000..a16083da --- /dev/null +++ b/middleware/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(StateMachine) \ No newline at end of file diff --git a/middleware/StateMachine/CMakeLists.txt b/middleware/StateMachine/CMakeLists.txt new file mode 100644 index 00000000..7609b191 --- /dev/null +++ b/middleware/StateMachine/CMakeLists.txt @@ -0,0 +1,47 @@ + +include(${CMAKE_SOURCE_DIR}/build/global_config.cmake) +set(EXECUTABLE_OUTPUT_PATH ${EXEC_OUTPUT_PATH}) +set(LIBRARY_OUTPUT_PATH ${LIBS_OUTPUT_PATH}) + +include_directories( + ./src + ./include + ./src/OpenHarmony + ${UTILS_SOURCE_PATH}/StatusCode/include + ${UTILS_SOURCE_PATH}/Log/include + ${HAL_SOURCE_PATH}/include +) +#do not rely on any other library +#link_directories( +#) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +aux_source_directory(./src SRC_FILES) +aux_source_directory(./src/OpenHarmony SRC_FILES_OPENHARMONY) + +set(TARGET_NAME StateMachine) +add_library(${TARGET_NAME} STATIC ${SRC_FILES} ${SRC_FILES_OPENHARMONY}) + +target_link_libraries(${TARGET_NAME} ReturnCode Log) + +if ("${CLANG_TIDY_SUPPORT}" MATCHES "true") +add_custom_target( + StateMahince_code_check + COMMAND ${CLANG_TIDY_EXE} + -checks='${CLANG_TIDY_CHECKS}' + --header-filter=.* + --system-headers=false + ${SRC_FILES} + ${CLANG_TIDY_CONFIG} + -p ${CMAKE_SOURCE_DIR_IPCSDK}/cmake-shell-linux + WORKING_DIRECTORY ${MIDDLEWARE_SOURCE_PATH}/StateMachine +) +add_custom_command( + TARGET ${TARGET_NAME} + PRE_BUILD + COMMAND make StateMahince_code_check + WORKING_DIRECTORY ${PROJECT_ROOT_PATH}/cmake-shell-linux/ +) +endif() \ No newline at end of file diff --git a/middleware/StateMachine/README.md b/middleware/StateMachine/README.md new file mode 100644 index 00000000..300c6c17 --- /dev/null +++ b/middleware/StateMachine/README.md @@ -0,0 +1,26 @@ +# 1. 层次状态机 + +   层次状态机在事件队列的基础上进行状态管理,使得业务逻辑耦合度非常低。 + +## 1.1. 开源代码 + +   移植了鸿蒙开源项目当中的层次状态机代码进行二次封装改造而成。 + +源码目录: + +``` +middleware/ +├── CMakeLists.txt +└── StateMachine // 状态机中间件 + ├── CMakeLists.txt + ├── include + │   └── IStateMachine.h + ├── README.md + └── src + ├── IStateMachine.cpp + ├── OpenHarmony // 鸿蒙开源的状态机源码目录 + ├── StateMachineImpl.cpp + ├── StateMachineImpl.h + ├── StateMachineMakePtr.cpp + └── StateMachineMakePtr.h +``` \ No newline at end of file diff --git a/middleware/StateMachine/include/IStateMachine.h b/middleware/StateMachine/include/IStateMachine.h new file mode 100644 index 00000000..120fc0b3 --- /dev/null +++ b/middleware/StateMachine/include/IStateMachine.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 JIUYILIAN 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. + */ +#ifndef I_STATE_MACHINE_H +#define I_STATE_MACHINE_H +#include "StatusCode.h" +#include +class VStateMessage +{ +public: + VStateMessage() = default; + virtual ~VStateMessage() = default; +}; +class VStateMachineParam +{ +public: + VStateMachineParam() = default; + virtual ~VStateMachineParam() = default; + virtual int GetMessageName() const = 0; + virtual const std::shared_ptr &GetMessageObj(void) const = 0; +}; +class State +{ +public: + explicit State(const std::string &name) : mStateName(name) {} + virtual ~State() = default; + +public: + virtual void GoInState() = 0; + virtual void GoOutState() = 0; + virtual bool ExecuteStateMsg(VStateMachineParam *msg) = 0; + std::string GetStateName() { return mStateName; } + +private: + std::string mStateName; +}; +class VStateMachine +{ +public: + VStateMachine() = default; + virtual ~VStateMachine() = default; + virtual bool InitialStateMachine() { return false; } + virtual void StatePlus(State *state, State *upper) {} + virtual void SetFirstState(State *firstState) {} + virtual void StartStateMachine() {} + virtual void SendMessage(int msgName) {} + virtual void StopHandlerThread() {} + virtual void SendMessage(int msgName, const std::shared_ptr &messageObj) {} + virtual void MessageExecutedLater(int msgName, const std::shared_ptr &messageObj, int64_t delayTimeMs) {} + virtual void SwitchState(State *targetState) {} + virtual void StopTimer(int timerName) {} + virtual void DelayMessage(VStateMachineParam *msg) {} +}; +class IStateMachine +{ +public: + IStateMachine() = default; + virtual ~IStateMachine() = default; + static std::shared_ptr &GetInstance(std::shared_ptr *impl = nullptr); + virtual const StatusCode CreateStateMachine(std::shared_ptr &stateMachine) + { + return CreateStatusCode(STATUS_CODE_VIRTUAL_FUNCTION); + } +}; +bool CreateStateMachine(void); +#endif \ No newline at end of file diff --git a/middleware/StateMachine/src/IStateMachine.cpp b/middleware/StateMachine/src/IStateMachine.cpp new file mode 100644 index 00000000..951aa912 --- /dev/null +++ b/middleware/StateMachine/src/IStateMachine.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 JIUYILIAN 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 "IStateMachine.h" +#include "ILog.h" +#include +std::shared_ptr &IStateMachine::GetInstance(std::shared_ptr *impl) +{ + static std::shared_ptr instance = std::make_shared(); + static bool instanceChanging = false; + if (impl && false == instanceChanging) + { + instanceChanging = true; + if (instance.use_count() == 1) + { + LogInfo("Instance change succeed.\n"); + instance = *impl; + } + else + { + LogError("Instance change failed, using by some one.\n"); + } + instanceChanging = false; + } + if (instanceChanging) + { + static std::shared_ptr tmporaryInstance = std::make_shared(); + return tmporaryInstance; + } + return instance; +} \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/handler.cpp b/middleware/StateMachine/src/OpenHarmony/handler.cpp new file mode 100644 index 00000000..f21d5b46 --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/handler.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2021 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 "handler.h" +#include +#include +#include "ILog.h" + +#undef LOG_TAG +#define LOG_TAG "OHWIFI_HANDLER" + +// namespace OHOS { +// namespace Wifi { +Handler::Handler() : pMyQueue(nullptr), handleThread(0), isRunning(true) +{} + +Handler::~Handler() +{ + LogInfo("Handler::~Handler\n"); + StopHandlerThread(); + return; +} + +bool Handler::InitialHandler() +{ + if (handleThread != 0) { + return true; + } + if (pMyQueue == nullptr) { + pMyQueue = std::make_unique(); + if (pMyQueue == nullptr) { + LogError("pMyQueue alloc failed.\n"); + return false; + } + } + + int ret = pthread_create(&handleThread, nullptr, RunHandleThreadFunc, this); + if (ret < 0) { + LogError("pthread_create failed.\n"); + return false; + } + + return true; +} + +void Handler::StopHandlerThread() +{ + LogInfo("Handler::StopHandlerThread\n"); + if (isRunning) { + isRunning = false; + if (pMyQueue != nullptr) { + pMyQueue->StopQueueLoop(); + } + + if (handleThread != 0) { + pthread_join(handleThread, nullptr); + } + } + + return; +} + +void *Handler::RunHandleThreadFunc(void *pInstance) +{ + if (pInstance == nullptr) { + LogError("pInstance is null.\n"); + return nullptr; + } + + Handler *pHandler = (Handler *)pInstance; + pHandler->GetAndDistributeMessage(); + + return nullptr; +} + +void Handler::GetAndDistributeMessage() +{ + if (pMyQueue == nullptr) { + LogError("pMyQueue is null.\n"); + return; + } + + while (isRunning) { + InternalMessage *msg = pMyQueue->GetNextMessage(); + if (msg == nullptr) { + LogError("GetNextMessage failed.\n"); + continue; + } + + DistributeMessage(msg); + MessageManage::GetInstance().ReclaimMsg(msg); + } + + return; +} + +void Handler::SendMessage(InternalMessage *msg) +{ + if (msg == nullptr) { + LogError("Handler::SendMessage: msg is null.\n"); + return; + } + + // LogInfo("Handler::SendMessage msg:%d\n", msg->GetMessageName()); + MessageExecutedLater(msg, 0); + return; +} + +void Handler::MessageExecutedLater(InternalMessage *msg, int64_t delayTimeMs) +{ + if (msg == nullptr) { + LogError("Handler::MessageExecutedLater: msg is null.\n"); + return; + } + + // LogInfo("Handler::MessageExecutedLater msg:%d\n", msg->GetMessageName()); + int64_t delayTime = delayTimeMs; + if (delayTime < 0) { + delayTime = 0; + } + + /* Obtains the current time, accurate to milliseconds. */ + struct timeval curTime = {0, 0}; + if (gettimeofday(&curTime, nullptr) != 0) { + LogError("gettimeofday failed.\n"); + MessageManage::GetInstance().ReclaimMsg(msg); + return; + } + int64_t nowTime = static_cast(curTime.tv_sec) * USEC_1000 + curTime.tv_usec / USEC_1000; + + MessageExecutedAtTime(msg, nowTime + delayTime); + return; +} + +void Handler::MessageExecutedAtTime(InternalMessage *msg, int64_t execTime) +{ + if (msg == nullptr) { + LogError("Handler::MessageExecutedAtTime: msg is null.\n"); + return; + } + + // LogInfo("Handler::MessageExecutedAtTime msg: %d\n", msg->GetMessageName()); + if (pMyQueue == nullptr) { + LogError("pMyQueue is null.\n"); + MessageManage::GetInstance().ReclaimMsg(msg); + return; + } + + if (pMyQueue->AddMessageToQueue(msg, execTime) != true) { + LogError("AddMessageToQueue failed.\n"); + return; + } + + return; +} + +void Handler::PlaceMessageTopOfQueue(InternalMessage *msg) +{ + if (msg == nullptr) { + LogError("Handler::PlaceMessageTopOfQueue: msg is null.\n"); + return; + } + + // LogInfo("Handler::PlaceMessageTopOfQueue msg: %d\n", msg->GetMessageName()); + if (pMyQueue == nullptr) { + LogError("pMyQueue is null.\n"); + MessageManage::GetInstance().ReclaimMsg(msg); + return; + } + + if (!pMyQueue->AddMessageToQueue(msg, 0)) { + LogError("AddMessageToQueue failed.\n"); + return; + } + + return; +} + +void Handler::DeleteMessageFromQueue(int messageName) +{ + // LogInfo("Handler::DeleteMessageFromQueue msg is: %d\n", messageName); + if (pMyQueue == nullptr) { + LogError("pMyQueue is null.\n"); + return; + } + + if (!pMyQueue->DeleteMessageFromQueue(messageName)) { + LogError("DeleteMessageFromQueue failed.\n"); + return; + } + + return; +} + +void Handler::DistributeMessage(InternalMessage *msg) +{ + if (msg == nullptr) { + return; + } + ExecuteMessage(msg); + return; +} +// } // namespace Wifi +// } // namespace OHOS \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/handler.h b/middleware/StateMachine/src/OpenHarmony/handler.h new file mode 100644 index 00000000..85e13633 --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/handler.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef OHOS_HANDLER_H +#define OHOS_HANDLER_H + +#include +#include "internal_message.h" +#include "message_queue.h" + +// namespace OHOS { +// namespace Wifi { +const int USEC_1000 = 1000; + +class Handler { +public: + /** + * @Description : Construct a new Handler:: Handler object. + * + */ + Handler(); + + /** + * @Description : Destroy the Handler:: Handler object. + * + */ + virtual ~Handler(); + + /** + * @Description : Initialize Handler + * + * @return true : Initialize Handler success, false: Initialize Handler failed. + */ + bool InitialHandler(); + + /** + * @Description : Thread processing function + * + * @param pInstance - Handler Instance pointer.[in] + */ + static void *RunHandleThreadFunc(void *pInstance); + + /** + * @Description :Stop the thread for obtaining messages. + * + */ + void StopHandlerThread(); + + /** + * @Description : Send a message and place the message in the message queue. + * + * @param msg - Message to be sent.[in] + */ + void SendMessage(InternalMessage *msg); + + /** + * @Description : Send a message, place the message in the message queue, and + process the message after delayTimeMs is delayed. + * + * @param msg - Message to be sent.[in] + * @param delayTimeMs - Delay Time.[in] + */ + void MessageExecutedLater(InternalMessage *msg, int64_t delayTimeMs); + + /** + * @Description : Send a message, place the message in the message queue, and + process the message at the execTime time point. + * + * @param msg - Message to be sent.[in] + * @param execTime - Time when a message is processed.[in] + */ + void MessageExecutedAtTime(InternalMessage *msg, int64_t execTime); + + /** + * @Description : Send a message and place the message at the top of the message queue. + * + * @param msg - Message to be sent.[in] + */ + void PlaceMessageTopOfQueue(InternalMessage *msg); + + /** + * @Description : Delete messages from the queue. + * + * @param messageName - Name of the message to be deleted.[in] + */ + void DeleteMessageFromQueue(int messageName); + + /** + * @Description : Distributing Messages. + * + * @param msg - Messages to be processed.[in] + */ + void DistributeMessage(InternalMessage *msg); + + /** + * @Description : Invoke the ExecuteStateMsg interface of the current state + to process messages sent to the state machine. The entry/exit + of the state machine is also called, and the delayed message + is put back into queue when transitioning to a new state. + * + * @param msg - Messages.[in] + */ + virtual void ExecuteMessage(InternalMessage *msg) = 0; + + /** + * @Description : Obtains messages from the message queue, distributes the + messages, and recycles the messages. + * + */ + void GetAndDistributeMessage(); + +private: + /* message queue. */ + std::unique_ptr pMyQueue; + /* Thread handle. */ + pthread_t handleThread; + + /* Running flag. */ + bool isRunning; +}; +// } // namespace Wifi +// } // namespace OHOS +#endif \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/internal_message.cpp b/middleware/StateMachine/src/OpenHarmony/internal_message.cpp new file mode 100644 index 00000000..93317dc1 --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/internal_message.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2021 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 "internal_message.h" +// #include "securec.h" +#include "ILog.h" + +#undef LOG_TAG +#define LOG_TAG "OHWIFI_INTERNAL_MESSAGE" + +// namespace OHOS { +// namespace Wifi { +void MessageBody::SaveIntData(int data) +{ + intArray_.push_back(data); + return; +} + +void MessageBody::SaveStringData(std::string data) +{ + stringArray_.push_back(data); + return; +} + +int MessageBody::GetIntData() +{ + if (intArray_.empty()) { + LogError("intArray is null.\n"); + return 0; + } + + int tmp = intArray_.front(); + intArray_.pop_front(); + return tmp; +} + +std::string MessageBody::GetStringData() +{ + std::string tmp; + if (stringArray_.empty()) { + LogError("stringArray is null.\n"); + return tmp; + } + + tmp = stringArray_.front(); + stringArray_.pop_front(); + return tmp; +} + +void MessageBody::ClearAllData() +{ + intArray_.clear(); + stringArray_.clear(); + return; +} + +void MessageBody::CopyMessageBody(const MessageBody &origBody) +{ + intArray_.assign(origBody.intArray_.begin(), origBody.intArray_.end()); + stringArray_.assign(origBody.stringArray_.begin(), origBody.stringArray_.end()); + + return; +} + +InternalMessage::InternalMessage() + : mMsgName(0), + mParam1(0), + mParam2(0), + pNextMsg(nullptr), + mHandleTime(0) +{} + +InternalMessage::~InternalMessage() +{ +} + +int InternalMessage::GetMessageName() const +{ + return mMsgName; +} + +int InternalMessage::GetParam1() const +{ + return mParam1; +} + +int InternalMessage::GetParam2() const +{ + return mParam2; +} + +int InternalMessage::GetIntFromMessage() +{ + return mMessageBody.GetIntData(); +} + +std::string InternalMessage::GetStringFromMessage() +{ + return mMessageBody.GetStringData(); +} + +const MessageBody &InternalMessage::GetMessageBody() const +{ + return mMessageBody; +} + +void InternalMessage::CopyMessageBody(const MessageBody &origBody) +{ + mMessageBody.CopyMessageBody(origBody); + return; +} + +InternalMessage *InternalMessage::GetNextMsg() const +{ + return pNextMsg; +} + +int64_t InternalMessage::GetHandleTime() const +{ + return mHandleTime; +} + +void InternalMessage::SetMessageName(int msgName) +{ + mMsgName = msgName; + return; +} + +void InternalMessage::SetParam1(int param1) +{ + mParam1 = param1; + return; +} + +void InternalMessage::SetParam2(int param2) +{ + mParam2 = param2; + return; +} + +void InternalMessage::ReleaseMessageObj() +{ + mMessageObj.reset(); + return; +} + +void InternalMessage::AddIntMessageBody(int data) +{ + mMessageBody.SaveIntData(data); + return; +} + +void InternalMessage::AddStringMessageBody(std::string data) +{ + mMessageBody.SaveStringData(data); + return; +} + +void InternalMessage::ClearMessageBody() +{ + mMessageBody.ClearAllData(); + return; +} + +void InternalMessage::SetNextMsg(InternalMessage *nextMsg) +{ + pNextMsg = nextMsg; + return; +} + +void InternalMessage::SetHandleTime(int64_t time) +{ + mHandleTime = time; + return; +} + +std::unique_ptr MessageManage::msgManage; + +MessageManage &MessageManage::GetInstance() +{ + if (msgManage.get() == nullptr) { + msgManage = std::make_unique(); + } + return *msgManage; +} + +MessageManage::MessageManage() : pMsgPool(nullptr), mMsgPoolSize(0) +{} + +MessageManage::~MessageManage() +{ + ReleasePool(); + return; +} + +InternalMessage *MessageManage::CreateMessage() +{ + { + std::unique_lock lock(mPoolMutex); + if (pMsgPool != nullptr) { + InternalMessage *m = pMsgPool; + pMsgPool = m->GetNextMsg(); + m->SetNextMsg(nullptr); + mMsgPoolSize--; + return m; + } + } + + auto pMessage = new (std::nothrow) InternalMessage(); + return pMessage; +} + +InternalMessage *MessageManage::CreateMessage(const InternalMessage *orig) +{ + InternalMessage *m = CreateMessage(); + if (m == nullptr) { + return nullptr; + } + + m->SetMessageName(orig->GetMessageName()); + m->SetParam1(orig->GetParam1()); + m->SetParam2(orig->GetParam2()); + m->SetMessageObj(orig->GetMessageObj()); + m->CopyMessageBody(orig->GetMessageBody()); + + return m; +} + +InternalMessage *MessageManage::CreateMessage(int messageName) +{ + InternalMessage *m = CreateMessage(); + if (m == nullptr) { + return nullptr; + } + + m->SetMessageName(messageName); + return m; +} + +InternalMessage *MessageManage::CreateMessage(int messageName, const std::shared_ptr &messageObj) +{ + InternalMessage *m = CreateMessage(); + if (m == nullptr) { + return nullptr; + } + + m->SetMessageName(messageName); + + m->SetMessageObj(messageObj); + return m; +} + +InternalMessage *MessageManage::CreateMessage(int messageName, int param1, int param2) +{ + InternalMessage *m = CreateMessage(); + if (m == nullptr) { + return nullptr; + } + + m->SetMessageName(messageName); + m->SetParam1(param1); + m->SetParam2(param2); + return m; +} + +InternalMessage *MessageManage::CreateMessage(int messageName, int param1, int param2, const std::shared_ptr &messageObj) +{ + InternalMessage *m = CreateMessage(); + if (m == nullptr) { + return nullptr; + } + + m->SetMessageName(messageName); + m->SetParam1(param1); + m->SetParam2(param2); + m->SetMessageObj(messageObj); + return m; +} + +void MessageManage::ReclaimMsg(InternalMessage *m) +{ + if (m == nullptr) { + return; + } + + m->SetMessageName(0); + m->SetParam1(0); + m->SetParam2(0); + m->ReleaseMessageObj(); + m->ClearMessageBody(); + + { + std::unique_lock lock(mPoolMutex); + if (mMsgPoolSize < MAX_MSG_NUM_IN_POOL) { + m->SetNextMsg(pMsgPool); + pMsgPool = m; + mMsgPoolSize++; + return; + } + } + + delete m; + m = nullptr; + return; +} + +void MessageManage::ReleasePool() +{ + std::unique_lock lock(mPoolMutex); + InternalMessage *current = pMsgPool; + InternalMessage *next = nullptr; + while (current != nullptr) { + next = current->GetNextMsg(); + delete current; + current = next; + } + + return; +} +// } // namespace Wifi +// } // namespace OHOS \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/internal_message.h b/middleware/StateMachine/src/OpenHarmony/internal_message.h new file mode 100644 index 00000000..19722909 --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/internal_message.h @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef OHOS_INTERNAL_MESSAGE_H +#define OHOS_INTERNAL_MESSAGE_H +#include "IStateMachine.h" +#include +#include +#include +#include +#include +// #include + +// namespace OHOS { +// namespace Wifi { +const int MAX_POOL_SIZE_INIT = 50; +class MessageBody { +public: + /** + * @Description : Save an Integer Data. + * + * @param data - Integer Data.[in] + */ + void SaveIntData(int data); + + /** + * @Description : Save a String Data. + * + * @param data - String Data.[in] + */ + void SaveStringData(std::string data); + + /** + * @Description : Get an Integer Data. + * + * @return int + */ + int GetIntData(); + + /** + * @Description : Get a String Data. + * + * @return std::string + */ + std::string GetStringData(); + + /** + * @Description : Clear all Data. + * + */ + void ClearAllData(); + + /** + * @Description : Copy a message body. + * + * @param origBody - Source Message Body.[in] + */ + void CopyMessageBody(const MessageBody &origBody); + +private: + /* Integer data. */ + std::list intArray_; + /* String data. */ + std::list stringArray_; +}; + +class InternalMessage : public VStateMachineParam { +public: + /** + * @Description : Construct a new Internal Message object. + * + */ + InternalMessage(); + + /** + * @Description Destroy the Internal Message object. + * + */ + ~InternalMessage(); + + /** + * @Description : Get message name. + * + * @return int + */ + int GetMessageName() const override; + + /** + * @Description : Obtains the first parameter in the message body. + * + * @return int + */ + int GetParam1() const; + + /** + * @Description : Obtains the second parameter in the message body. + * + * @return int + */ + int GetParam2() const; + + /** + * @Description : Obtains Integer data from message. + * + * @return int + */ + int GetIntFromMessage(); + + /** + * @Description : Obtains Sting data from message. + * + * @return std::string + */ + std::string GetStringFromMessage(); + + /** + * @Description : Obtains message body. + * + * @return MessageBody& + */ + const MessageBody &GetMessageBody() const; + + /** + * @Description : Copy message body. + * + * @param origBody - Source Message Body.[in] + */ + void CopyMessageBody(const MessageBody &origBody); + + /** + * @Description : Get next message. + * + * @return InternalMessage* + */ + InternalMessage *GetNextMsg() const; + + /** + * @Description : Obtains time. + * + * @return int64_t + */ + int64_t GetHandleTime() const; + + /** + * @Description : Set message name. + * + * @param msgName - Message name.[in] + */ + void SetMessageName(int msgName); + + /** + * @Description : Set the first parameter in the message body. + * + * @param param1 - The first parameter.[in] + */ + void SetParam1(int param1); + + /** + * @Description : Set the second parameter in the message body. + * + * @param param2 - The second parameter.[in] + */ + void SetParam2(int param2); + + /** + * @DescriptionSet the Message Obj object - brief + * @tparam - T Custom type to be set + * @param messageObj - User-defined data to be set + */ + // template + // void SetMessageObj(const T &messageObj) + // { + // mMessageObj = messageObj; + // } + + /** + * @DescriptionSet the Message Obj object - brief + * @tparam - T Custom type to be set + * @param messageObj - User-defined data to be set + */ + // template + // void SetMessageObj(T &&messageObj) + // { + // mMessageObj = T(messageObj); + // } + + void SetMessageObj(const std::shared_ptr &messageObj) + { + mMessageObj = messageObj; + } + + /** + * @DescriptionGet the Message Obj object + * @tparam - T Custom type to be set + * @param messageObj - Gets data of an actual specific object. + * @return - bool true:success   false:failed   + */ + // template + // bool GetMessageObj(T &messageObj) const + // { + // messageObj = std::any_cast(mMessageObj); + // return true; + // } + bool GetMessageObj(std::shared_ptr &messageObj) const + { + // TODO: + // messageObj = std::any_cast(mMessageObj); + return true; + } + + // const std::any &GetMessageObj(void) const + // { + // return mMessageObj; + // } + const std::shared_ptr &GetMessageObj(void) const override + { + return mMessageObj; + } + + /** + * @Description : Release Message Object. + * + */ + void ReleaseMessageObj(); + + /** + * @Description : Add integer message body. + * + * @param data - Integer data.[in] + */ + void AddIntMessageBody(int data); + + /** + * @Description : Add string message body. + * + * @param data - String data.[in] + */ + void AddStringMessageBody(std::string data); + + /** + * @Description : Clear message body. + * + */ + void ClearMessageBody(); + + /** + * @Description : Sets next message. + * + * @param next - The next message.[in] + */ + void SetNextMsg(InternalMessage *nextMsg); + + /** + * @Description : Set the time. + * + * @param time - Time.[in] + */ + void SetHandleTime(int64_t time); + +private: + /* Message Name */ + int mMsgName; + /* Parameter 1 */ + int mParam1; + /* Parameter 2 */ + int mParam2; + /* any message obj. */ + // std::any mMessageObj; + std::shared_ptr mMessageObj; + /* Message bodies that cannot be directly copied */ + MessageBody mMessageBody; + /* Next message in the resource pool or message queue */ + InternalMessage *pNextMsg; + /* Message execution time */ + int64_t mHandleTime; +}; +class MessageManage { +public: + /** + * @Description : Obtains a single instance. + * + * @return MessageManage& + */ + static MessageManage &GetInstance(); + + /** + * @Description : Message obtaining function. + * + * @return InternalMessage* + */ + InternalMessage *CreateMessage(); + + /** + * @Description : Obtain original messages. + * + * @param orig - Original messages.[in] + * @return InternalMessage* + */ + InternalMessage *CreateMessage(const InternalMessage *orig); + + /** + * @Description : Obtains the message name. + * + * @param messageName - Message name.[in] + * @return InternalMessage* + */ + InternalMessage *CreateMessage(int messageName); + + /** + * @Description :Obtaining Message Information. + * + * @param messageName - Message name.[in] + * @param messageObj - Message pointer.[in] + * @return InternalMessage* + */ + InternalMessage *CreateMessage(int messageName, const std::shared_ptr &messageObj); + + /** + * @Description : Obtaining Message Information. + * + * @param messageName - Message name.[in] + * @param param1 - param1.[in] + * @param param2 - param2.[in] + * @return InternalMessage* + */ + InternalMessage *CreateMessage(int messageName, int param1, int param2); + + /** + * @Description : Obtaining Message Information. + * + * @param messageName - Message name.[in] + * @param param1 - param1.[in] + * @param param2 - param2.[in] + * @param messageObj - Message pointer.[in] + * @return InternalMessage* + */ + InternalMessage *CreateMessage(int messageName, int param1, int param2, const std::shared_ptr &messageObj); + + /** + * @Description :Recycle message. + * + * @param m - message.[in] + */ + void ReclaimMsg(InternalMessage *m); + + /** + * @Description : Release pool. + * + */ + + void ReleasePool(); + + /** + * @Description : Construct a new Message Manage object. + * + */ + MessageManage(); + + /** + * @Description : Destroy the Message Manage object. + * + */ + ~MessageManage(); + +private: + /* Maximum number of messages in the message resource pool */ + const int MAX_MSG_NUM_IN_POOL = 50; + /* Message resource pool */ + InternalMessage *pMsgPool; + /* Number of messages in the message resource pool */ + int mMsgPoolSize; + /* Mutex for operating the message resource pool */ + std::mutex mPoolMutex; + static std::unique_ptr msgManage; +}; +// } // namespace Wifi +// } // namespace OHOS +#endif diff --git a/middleware/StateMachine/src/OpenHarmony/message_queue.cpp b/middleware/StateMachine/src/OpenHarmony/message_queue.cpp new file mode 100644 index 00000000..2962c1ff --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/message_queue.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2021 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 "message_queue.h" +#include +#include "ILog.h" +// #include "wifi_errcode.h" + +#undef LOG_TAG +#define LOG_TAG "OHWIFI_MESSAGE_QUEUE" + +// namespace OHOS { +// namespace Wifi { +MessageQueue::MessageQueue() : pMessageQueue(nullptr), mIsBlocked(false), mNeedQuit(false) +{} + +MessageQueue::~MessageQueue() +{ + LogInfo("MessageQueue::~MessageQueue\n"); + /* Releasing Messages in a Queue */ + std::unique_lock lock(mMtxQueue); + InternalMessage *current = pMessageQueue; + InternalMessage *next = nullptr; + while (current != nullptr) { + next = current->GetNextMsg(); + delete current; + current = next; + } + + return; +} + +bool MessageQueue::AddMessageToQueue(InternalMessage *message, int64_t handleTime) +{ + if (message == nullptr) { + LogError("message is null.\n"); + return false; + } + + if (mNeedQuit) { + MessageManage::GetInstance().ReclaimMsg(message); + LogError("Already quit the message queue.\n"); + return false; + } + + message->SetHandleTime(handleTime); + bool needWake = false; + /* + * If the queue is empty, the current message needs to be executed + * immediately, or the execution time is earlier than the queue header, the + * message is placed in the queue header and is woken up when the queue is + * blocked. + */ + { + std::unique_lock lck(mMtxQueue); + InternalMessage *pTop = pMessageQueue; + if (pTop == nullptr || handleTime == 0 || handleTime < pTop->GetHandleTime()) { + message->SetNextMsg(pTop); + pMessageQueue = message; + needWake = mIsBlocked; + /* Inserts messages in the middle of the queue based on the execution time. */ + } else { + InternalMessage *pPrev = nullptr; + InternalMessage *pCurrent = pTop; + while (pCurrent != nullptr) { + pPrev = pCurrent; + pCurrent = pCurrent->GetNextMsg(); + if (pCurrent == nullptr || handleTime < pCurrent->GetHandleTime()) { + message->SetNextMsg(pCurrent); + pPrev->SetNextMsg(message); + break; + } + } + } + } + + /* Wake up the process. */ + if (needWake) { + std::unique_lock lck(mMtxBlock); + mCvQueue.notify_all(); + mIsBlocked = false; + } + + return true; +} + +bool MessageQueue::DeleteMessageFromQueue(int messageName) +{ + std::unique_lock lck(mMtxQueue); + + InternalMessage *pTop = pMessageQueue; + if (pTop == nullptr) { + return true; + } + + InternalMessage *pCurrent = pTop; + while (pCurrent != nullptr) { + InternalMessage *pPrev = pCurrent; + pCurrent = pCurrent->GetNextMsg(); + if ((pCurrent != nullptr) && (pCurrent->GetMessageName() == messageName)) { + InternalMessage *pNextMsg = pCurrent->GetNextMsg(); + pPrev->SetNextMsg(pNextMsg); + MessageManage::GetInstance().ReclaimMsg(pCurrent); + pCurrent = pNextMsg; + } + } + + if (pTop->GetMessageName() == messageName) { + pMessageQueue = pTop->GetNextMsg(); + MessageManage::GetInstance().ReclaimMsg(pTop); + } + + return true; +} + +InternalMessage *MessageQueue::GetNextMessage() +{ + // LogInfo("MessageQueue::GetNextMessage\n"); + int nextBlockTime = 0; + + while (!mNeedQuit) { + /* Obtains the current time, accurate to milliseconds. */ + struct timeval curTime = {0, 0}; + if (gettimeofday(&curTime, nullptr) != 0) { + LogError("gettimeofday failed.\n"); + return nullptr; + } + int64_t nowTime = static_cast(curTime.tv_sec) * TIME_USEC_1000 + curTime.tv_usec / TIME_USEC_1000; + + { + std::unique_lock lck(mMtxQueue); + InternalMessage *curMsg = pMessageQueue; + mIsBlocked = true; + if (curMsg != nullptr) { + if (nowTime < curMsg->GetHandleTime()) { + /* The execution time of the first message is not reached. + The remaining time is blocked here. */ + nextBlockTime = curMsg->GetHandleTime() - nowTime; + } else { + /* Return the first message. */ + mIsBlocked = false; + pMessageQueue = curMsg->GetNextMsg(); + curMsg->SetNextMsg(nullptr); + return curMsg; + } + } else { + /* If there's no message, check it every 30 seconds. */ + nextBlockTime = TIME_INTERVAL; + } + } + + std::unique_lock lck(mMtxBlock); + if (mIsBlocked && (!mNeedQuit)) { + if (mCvQueue.wait_for(lck, std::chrono::milliseconds(nextBlockTime)) == std::cv_status::timeout) { + // LogInfo("mCvQueue timeout.\n"); + } else { + // LogInfo("Wake up.\n"); + } + } + mIsBlocked = false; + } + + LogError("Already quit the message queue.\n"); + return nullptr; +} + +void MessageQueue::StopQueueLoop() +{ + mNeedQuit = true; + if (mIsBlocked) { + std::unique_lock lck(mMtxBlock); + mCvQueue.notify_all(); + mIsBlocked = false; + } + + return; +} +// } // namespace Wifi +// } // namespace OHOS \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/message_queue.h b/middleware/StateMachine/src/OpenHarmony/message_queue.h new file mode 100644 index 00000000..290174eb --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/message_queue.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef OHOS_MESSAGE_QUEUE_H +#define OHOS_MESSAGE_QUEUE_H + +#include +#include +#include +#include "internal_message.h" + +// namespace OHOS { +// namespace Wifi { +#define TIME_USEC_1000 1000 +#define TIME_INTERVAL 30000 +class MessageQueue { +public: + /** + * @Description : Construct a new Message Queue object. + * + */ + MessageQueue(); + + /** + * @Description : Destroy the Message Queue object. + * + */ + ~MessageQueue(); + + /** + * @Description : Inserting Messages into Queues. + * + * @param message - Message to be inserted.[in] + * @param handleTime - Message execution time.[in] + * @return true : success, false : failed. + */ + bool AddMessageToQueue(InternalMessage *message, int64_t handleTime); + + /** + * @Description : Delete messages from the queue. + * + * @param messageName - Name of the message to be deleted.[in] + * @return true : success, false : failed. + */ + bool DeleteMessageFromQueue(int messageName); + + /** + * @Description : Obtain messages from the queue for processing. + * If no message is found, the system blocks the messages. + * + */ + InternalMessage *GetNextMessage(); + + /** + * @Description : Obtain messages from the queue for processing. + * If no message is found, the system blocks the messages. + */ + void StopQueueLoop(); + +private: + /* Message Queuing */ + InternalMessage *pMessageQueue; + /* No messages to be executed, blocking */ + bool mIsBlocked; + /* Exit Loop */ + bool mNeedQuit; + /* Thread lock of operation queue */ + std::mutex mMtxQueue; + /* Blocked thread lock */ + std::mutex mMtxBlock; + /* blocking condition variable */ + std::condition_variable mCvQueue; +}; +// } // namespace Wifi +// } // namespace OHOS +#endif \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/state.cpp b/middleware/StateMachine/src/OpenHarmony/state.cpp new file mode 100644 index 00000000..1be2cb17 --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/state.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 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 "IStateMachine.h" + +#undef LOG_TAG +#define LOG_TAG "OHWIFI_STATE" + +// namespace OHOS { +// namespace Wifi { +// State::State(const std::string &name) : mStateName(name) +// {} + +// State::~State() +// {} + +// std::string State::GetStateName() +// { +// return mStateName; +// } +// } // namespace Wifi +// } // namespace OHOS \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/state.h b/middleware/StateMachine/src/OpenHarmony/state.h new file mode 100644 index 00000000..8bcf8d54 --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/state.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef OHOS_STATE_H +#define OHOS_STATE_H + +#include +#include "message_queue.h" + +// namespace OHOS { +// namespace Wifi { +// } // namespace Wifi +// } // namespace OHOS +#endif \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/state_machine.cpp b/middleware/StateMachine/src/OpenHarmony/state_machine.cpp new file mode 100644 index 00000000..0bce11ff --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/state_machine.cpp @@ -0,0 +1,686 @@ +/* + * 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::SetFirstState(State *firstState) +{ + if (pStateMachineHandler == nullptr) { + LogError("Start StateMachine failed, pStateMachineHandler is nullptr!\n"); + return; + } + + pStateMachineHandler->SetFirstState(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(VStateMachineParam *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::SetFirstState(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((VStateMachineParam *)(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 \ No newline at end of file diff --git a/middleware/StateMachine/src/OpenHarmony/state_machine.h b/middleware/StateMachine/src/OpenHarmony/state_machine.h new file mode 100644 index 00000000..df0afc0a --- /dev/null +++ b/middleware/StateMachine/src/OpenHarmony/state_machine.h @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef OHOS_STA_MACHINE_H +#define OHOS_STA_MACHINE_H + +#include +#include +#include +#include "handler.h" +#include "message_queue.h" +#include "IStateMachine.h" + +// namespace OHOS { +// namespace Wifi { +#define CMD_SET_OPERATIONAL_MODE 1 + +class StateMachineHandler; +class StateMachine : public VStateMachine +{ +public: + /** + * @Description : StateMachine Initialization Function + * + * @return true :success, false : failed. + */ + bool InitialStateMachine() override; + + /** + * @Description : Start StateMachine. + * + */ + void StartStateMachine() override; + + /** + * @Description : Set Handler. + * + * @param handler - StateMachineHandler instance.[in] + */ + void SetHandler(StateMachineHandler *handler); + + /** + * @Description : The Message is not handled. + * + * @param msg - Message object.[in] + */ + void NotExecutedMessage(const InternalMessage *msg); + + /** + * @Description Stop Handler Thread. + * + */ + void StopHandlerThread() override; + + /** + * @Description : Start the timer. + * + * @param timerName - Timer Name.[in] + * @param interval - Timer duration, in milliseconds.[in] + */ + virtual void StartTimer(int timerName, int64_t interval); + + /** + * @Description : Stop the timer. + * + * @param timerName - Timer Name.[in] + */ + virtual void StopTimer(int timerName) override; + + /** + * @Description : Construct internal messages. + * + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(); + + /** + * @Description : Construct an information message based on + * the original message. + * + * @param orig - Original message.[in] + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(const InternalMessage *orig); + + /** + * @Description : Construct internal messages. + * + * @param msgName - Message Name.[in] + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(int msgName); + + /** + * @Description : Construct internal messages. + * + * @param msgName - Message Name.[in] + * @param param1 - Message parameters.[in] + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(int msgName, int param1); + + /** + * @Description : Construct internal messages. + * + * @param msgName - Message Name.[in] + * @param param1 - Message parameters.[in] + * @param param2 - Message parameters.[in] + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(int msgName, int param1, int param2); + + /** + * @Description : Construct internal messages. + * + * @param msgName - Message Name.[in] + * @param messageObj - User-defined data + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(int msgName, const std::shared_ptr &messageObj); + + /** + * @Description : Constructs internal messages. + * + * @param msgName - Message name.[in] + * @param param1 - First Message parameter.[in] + * @param param2 - Second Message parameter.[in] + * @param messageObj - User-defined data + * @return InternalMessage* : Pointer to the constructed internal message. + */ + InternalMessage *CreateMessage(int msgName, int param1, int param2, const std::shared_ptr &messageObj); + + /** + * @Description : Constructs internal messages and places the + * messages in the message queue of the state machine. + * + * @param msgName - Message name.[in] + */ + virtual void SendMessage(int msgName) override; + + /** + * @Description : Constructs internal messages and places the messages + * in the message queue of the state machine. + * + * @param msgName - Message name.[in] + * @param param1 - Message parameter.[in] + */ + virtual void SendMessage(int msgName, int param1); + + /** + * @Description : Constructs internal messages and places the messages + * in the message queue of the state machine. + * + * @param msgName - Message name.[in] + * @param param1 - Message parameter.[in] + * @param param2 - Message parameter.[in] + */ + virtual void SendMessage(int msgName, int param1, int param2); + + /** + * @Description : Puts messages into the message queue of the state machine. + * + * @param msg - Message to be sent.[in] + */ + virtual void SendMessage(InternalMessage *msg); + + /** + * @Description : Puts messages into the message queue of the state machine. + * + * @param msgName - Message Name.[in] + * @param messageObj - User-defined data + */ + virtual void SendMessage(int msgName, const std::shared_ptr &messageObj) override; + + /** + * @Description : Puts messages into the message queue of the state machine. + * + * @param msgName - Message Name.[in] + * @param param1 - Message parameters.[in] + * @param param2 - Message parameters.[in] + * @param messageObj - User-defined data + */ + virtual void SendMessage(int msgName, int param1, int param2, const std::shared_ptr &messageObj); + + /** + * @Description Constructs internal messages and places them in the + * message queue of the state machine. The messages are processed + * after the specified delay time. + * + * @param msgName - Message Name.[in] + * @param delayTimeMs - Delay time, in milliseconds.[in] + */ + void MessageExecutedLater(int msgName, int64_t delayTimeMs); + + /** + * @Description : Constructs internal messages and places them in the + * message queue of the state machine. The messages are processed + * after the specified delay time. + * + * @param msgName - Message Name.[in] + * @param param1 - Message parameters.[in] + * @param delayTimeMs - Delay time, in milliseconds.[in] + */ + void MessageExecutedLater(int msgName, int param1, int64_t delayTimeMs); + + /** + * @Description : Constructs internal messages and places them in the + * message queue of the state machine. The messages are processed + * after the specified delay time. + * + * @param msgName - Message Name.[in] + * @param param1 - Message parameters.[in] + * @param param2 - Message parameters.[in] + * @param delayTimeMs - Delay time, in milliseconds.[in] + */ + void MessageExecutedLater(int msgName, int param1, int param2, int64_t delayTimeMs); + + /** + * @Description : Constructs internal messages and places them in the + * message queue of the state machine. The messages are processed + * after the specified delay time. + * + * @param msg - Message to be sent.[in] + * @param delayTimeMs - Delay time, in milliseconds.[in] + */ + void MessageExecutedLater(InternalMessage *msg, int64_t delayTimeMs); + + /** + * @Description : Constructs internal messages and places them in the + * message queue of the state machine. The messages are processed + * after the specified delay time. + * + * @param msgName - Message Name.[in] + * @param messageObj -User-defined data + * @param delayTimeMs - Delay time, in milliseconds.[in] + */ + void MessageExecutedLater(int msgName, const std::shared_ptr &messageObj, int64_t delayTimeMs) override; + + /** + * @Description : Constructs internal messages and places them in the + * message queue of the state machine. The messages are processed + * after the specified delay time. + * + * @param msgName - Message Name.[in] + * @param param1 - Message parameters.[in] + * @param param2 - Message parameters.[in] + * @param messageObj - User-defined data + * @param delayTimeMs - Delay time, in milliseconds.[in] + */ + void MessageExecutedLater(int msgName, int param1, int param2, const std::shared_ptr &messageObj, int64_t delayTimeMs); + + /** + * @Description : Construct a new State Machine:: State Machine object. + * + * @param name - State name.[in] + */ + explicit StateMachine(const std::string &name); + + /** + * @Description : Destroy the State Machine:: State Machine object. + * + */ + virtual ~StateMachine(); + +protected: + /** + * @Description : Add state. + * + * @param state - state.[in] + * @param upper - upper state.[in] + */ + void StatePlus(State *state, State *upper) override; + + /** + * @Description : Remove state. + * + * @param state - state.[in] + */ + void StateDelete(State *state); + + /** + * @Description : Set first state. + * + * @param firstState - First state.[in] + */ + void SetFirstState(State *firstState) override; + + /** + * @Description : Transition to orther state. + * + * @param targetState - state.[in] + */ + void SwitchState(State *targetState) override; + + /** + * @Description : Delay Message. + * + * @param msg - Message object.[in] + */ + void DelayMessage(const InternalMessage *msg); + void DelayMessage(VStateMachineParam *msg) override; + +private: + StateMachineHandler *pStateMachineHandler; + std::string mStateName; +}; + +typedef struct StateInfo +{ + State *state; + StateInfo *upperStateInfo; + bool active; +} StateInfo; + +class StateMachineHandler : public Handler +{ +public: + using StateInfoMap = std::map; + using StateVector = std::vector; + using DelayedMessage = std::vector; + + /** + * @Description : Construct a new state machine Handler:: StateMachine Handler object. + * + * @param pStateMgr - Handler pointer.[in] + */ + explicit StateMachineHandler(StateMachine *pStateMgr); + + /** + * @Description : Destroy the StateMachine Handler:: StateMachine Handler object. + * + */ + ~StateMachineHandler(); + + /** + * @Description : StateMachineHandler Initialization Function. + * + * @return true : success, false : failed. + */ + bool InitialSmHandler(); + + /** + * @Description : Add a new state. + * + * @param state - State to be added.[in] + * @param upper - upper of state.[in] + * @return StateInfo* + */ + StateInfo *StatePlus(State *state, State *upper); + + /** + * @Description : Delete a state. + * + * @param state - State to be deleted.[in] + */ + void StateDelete(State *state); + + /** + * @Description : Sets the Initialization State. + * + * @param firstState - Initialization State.[in] + */ + void SetFirstState(State *firstState); + + /** + * @Description : State transition function. + * + * @param targetState - Destination State.[in] + */ + void SwitchState(State *targetState); + + /** + * @Description : Delay Message Processing Function. + * + * @param msg - Message body pointer.[in] + */ + void DelayMessage(const InternalMessage *msg); + // void DelayMessage(const std::shared_ptr &messageObj); + + /** + * @Description : The state machine is constructed. + * + */ + void BuildTreeComplete(); + +private: + /** + * @Description : Sets the initial state sequence. + * + */ + void BuildStateInitVector(); + + /** + * @Description : Writes the inactive upper states of targetState + * and targetState to the sequenceStateVector list. + * + * @param targetState - Target State Machine.[in] + * @return StateInfo* + */ + StateInfo *BuildSequenceStateVector(State *targetState); + + /** + * @Description : Move Delayed Message At Front Of Queue. + * + */ + void PlaceDelayedMsgQueueTop(); + + /** + * @Description : Release all messages in delayed Messages. + * + */ + void ReleaseDelayedMessages(); + + /** + * @Description : Fill the status in the sequential status + * list in reverse order. + * + * @return int + */ + int MoveSequenceToStateVector(); + + /** + * @Description : Invoke the ExecuteStateMsg interface of the current state + * to process messages sent to the state machine. The entry/exit of the + * state machine is also called, and the delayed messagei s put back + * into queue when transitioning to a new state. + * + * @param msg - Messages.[in] + */ + void ExecuteMessage(InternalMessage *msg) override; + + /** + * @Description : Clean up After Quitting. + * + */ + void ClearWhenQuit(); + + /** + * @Description : Performing Status Transitions. + * + * @param msgProcessedState - Message processing status.[in] + * @param msg - Messages.[in] + */ + void PerformSwitchState(State *msgProcessedState, InternalMessage *msg); + + /** + * @Description : Process messages. If the current state doesnot process it, + * the upper state processing is called, and so on. If all upper states + * are not processed, invoke the NotExecutedMessage method of the state machine. + * + * @param msg - Message body pointer.[in] + * @return State* + */ + State *ExecuteTreeStateMsg(InternalMessage *msg); + + /** + * @Description : Invoke GoOutState() for each state from the first + * state in the list to the public upper state. + * + * @param commonStateInfo - common upper state machine.[in] + */ + void CallTreeStateExits(StateInfo *commonStateInfo); + + /** + * @Description : Call the GoInState method from the start state + * index to the top of the state stack. + * + * @param index - Start state index of the + * state machine list. + */ + void CallTreeStateEnters(int index); + +private: + /* All state mappings of the state machine */ + StateInfoMap mStateInfoMap; + /* From child state to upper state list */ + StateVector mStateVector; + /* Top index of mStateVector */ + int mStateVectorTopIndex; + /* From upper state to child state list */ + StateVector mSequenceStateVector; + /* Top of mSequenceStateVector */ + int mSequenceStateVectorCount; + /* Delayed Message Queue */ + DelayedMessage mDelayedMessages; + /* State machine instance */ + StateMachine *pStateMachine; + /* Initial state */ + State *pFirstState; + /* Target Status */ + State *pTargetState; + /* StateMachine exit or not */ + bool mQuitFlag; + /* Whether the state machine has been built */ + bool mBuildCompleteFlag; + /* + * All State exit/enter calls are true before the + * last enter call in the target state. + */ + bool mSwitchingStateFlag; + /* Current Message */ + InternalMessage *pCurrentMsg; +}; +// } // namespace Wifi +// } // namespace OHOS +#endif \ No newline at end of file diff --git a/middleware/StateMachine/src/StateMachineImpl.cpp b/middleware/StateMachine/src/StateMachineImpl.cpp new file mode 100644 index 00000000..3443938b --- /dev/null +++ b/middleware/StateMachine/src/StateMachineImpl.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 JIUYILIAN 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 "StateMachineImpl.h" +#include "StateMachineMakePtr.h" +const StatusCode StateMachineImpl::CreateStateMachine(std::shared_ptr &stateMachine) +{ + return StateMachineMakePtr::GetInstance()->CreateStateMachine(stateMachine); +} \ No newline at end of file diff --git a/middleware/StateMachine/src/StateMachineImpl.h b/middleware/StateMachine/src/StateMachineImpl.h new file mode 100644 index 00000000..46fd52e1 --- /dev/null +++ b/middleware/StateMachine/src/StateMachineImpl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 JIUYILIAN 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. + */ +#ifndef STATE_MACHINE_IMPL_H +#define STATE_MACHINE_IMPL_H +#include "IStateMachine.h" +class StateMachineImpl : public IStateMachine +{ +public: + StateMachineImpl() = default; + ~StateMachineImpl() = default; + const StatusCode CreateStateMachine(std::shared_ptr &stateMachine) override; +}; +#endif \ No newline at end of file diff --git a/middleware/StateMachine/src/StateMachineMakePtr.cpp b/middleware/StateMachine/src/StateMachineMakePtr.cpp new file mode 100644 index 00000000..f15ca56d --- /dev/null +++ b/middleware/StateMachine/src/StateMachineMakePtr.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 JIUYILIAN 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 "StateMachineMakePtr.h" +#include "ILog.h" +#include "state_machine.h" +#include "IStateMachine.h" +#include "StateMachineImpl.h" +#include +bool CreateStateMachine(void) +{ + auto instance = std::make_shared(); + StatusCode code = StateMachineMakePtr::GetInstance()->CreateStateMachine(instance); + if (IsCodeOK(code)) + { + LogInfo("State machine instance is ok.\n"); + IStateMachine::GetInstance(&instance); + return true; + } + return false; +} +std::shared_ptr &StateMachineMakePtr::GetInstance(std::shared_ptr *impl) +{ + static auto instance = std::make_shared(); + if (impl) + { + instance = *impl; + } + return instance; +} +StatusCode StateMachineMakePtr::CreateStateMachine(std::shared_ptr &stateMachine) +{ + // TODO: need a name ? + auto tmp = std::make_shared("TODO"); + if (tmp) + { + stateMachine = std::move(tmp); + return CreateStatusCode(STATUS_CODE_OK); + } + LogError("Create state machine module failed.\n"); + return CreateStatusCode(STATUS_CODE_MAKE_SHARED_PTR_FAILED); +} +StatusCode StateMachineMakePtr::CreateStateMachine(std::shared_ptr &instance) +{ + auto tmp = std::make_shared(); + if (tmp) + { + instance = std::move(tmp); + return CreateStatusCode(STATUS_CODE_OK); + } + LogError("Create state machine module failed.\n"); + return CreateStatusCode(STATUS_CODE_MAKE_SHARED_PTR_FAILED); +} \ No newline at end of file diff --git a/middleware/StateMachine/src/StateMachineMakePtr.h b/middleware/StateMachine/src/StateMachineMakePtr.h new file mode 100644 index 00000000..978ca1a3 --- /dev/null +++ b/middleware/StateMachine/src/StateMachineMakePtr.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 JIUYILIAN 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. + */ +#ifndef STATE_MACHINE_MAKE_PTR_H +#define STATE_MACHINE_MAKE_PTR_H +#include "StatusCode.h" +#include "IStateMachine.h" +#include +class StateMachineMakePtr +{ +public: + StateMachineMakePtr() = default; + virtual ~StateMachineMakePtr() = default; + static std::shared_ptr &GetInstance(std::shared_ptr *impl = nullptr); + virtual StatusCode CreateStateMachine(std::shared_ptr &stateMachine); + virtual StatusCode CreateStateMachine(std::shared_ptr &instance); +}; +#endif \ No newline at end of file diff --git a/utils/Log/include/ILog.h b/utils/Log/include/ILog.h index 9576fe6e..7995b16d 100644 --- a/utils/Log/include/ILog.h +++ b/utils/Log/include/ILog.h @@ -32,6 +32,13 @@ extern "C" #define LogWarning(...) GetLogIntance()->printf(GetLogIntance(), __FUNCTION__, __LINE__, LOG_TYPE_WARNING, __VA_ARGS__) #define LogError(...) GetLogIntance()->printf(GetLogIntance(), __FUNCTION__, __LINE__, LOG_TYPE_ERROR, __VA_ARGS__) #define LogTrace(...) GetLogIntance()->printf(GetLogIntance(), __FUNCTION__, __LINE__, LOG_TYPE_TRACE, __VA_ARGS__) +#if 1 // For OpenHarmony log, should delete finally.// TODO: +#define LOGD(...) +#define LOGI(...) +#define LOGW(...) +#define LOGE(...) +#define LOGF(...) +#endif typedef struct i_log ILog; typedef struct i_log { diff --git a/utils/StatusCode/include/StatusCode.h b/utils/StatusCode/include/StatusCode.h index ab45193f..1b0c5ba0 100644 --- a/utils/StatusCode/include/StatusCode.h +++ b/utils/StatusCode/include/StatusCode.h @@ -11,6 +11,7 @@ extern "C" STATUS_CODE_NOT_OK, STATUS_CODE_VIRTUAL_FUNCTION, STATUS_CODE_INVALID_PARAMENTER, + STATUS_CODE_MAKE_SHARED_PTR_FAILED, STATUS_CODE_END }; typedef struct status_code StatusCode;