| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * Copyright (c) 2018 Nest Labs, Inc. |
| * |
| * 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. |
| */ |
| |
| /** |
| * @file |
| * Defines the public interface for the Device Layer PlatformManager object. |
| */ |
| |
| #pragma once |
| |
| #include <app-common/zap-generated/cluster-objects.h> |
| #include <platform/CHIPDeviceBuildConfig.h> |
| #include <platform/CHIPDeviceEvent.h> |
| #include <system/PlatformEventSupport.h> |
| #include <system/SystemLayer.h> |
| |
| namespace chip { |
| |
| namespace Dnssd { |
| class DiscoveryImplPlatform; |
| } |
| |
| namespace DeviceLayer { |
| |
| class PlatformManagerImpl; |
| class ConnectivityManagerImpl; |
| class ConfigurationManagerImpl; |
| class TraitManager; |
| class ThreadStackManagerImpl; |
| class TimeSyncManager; |
| |
| namespace Internal { |
| class DeviceControlServer; |
| class FabricProvisioningServer; |
| class ServiceProvisioningServer; |
| class BLEManagerImpl; |
| template <class> |
| class GenericConfigurationManagerImpl; |
| template <class> |
| class GenericPlatformManagerImpl; |
| template <class> |
| class GenericPlatformManagerImpl_FreeRTOS; |
| template <class> |
| class GenericPlatformManagerImpl_POSIX; |
| template <class> |
| class GenericPlatformManagerImpl_Zephyr; |
| template <class> |
| class GenericConnectivityManagerImpl_Thread; |
| template <class> |
| class GenericThreadStackManagerImpl_OpenThread; |
| template <class> |
| class GenericThreadStackManagerImpl_OpenThread_LwIP; |
| } // namespace Internal |
| |
| // Maximum length of vendor defined name or prefix of the software thread that is |
| // static for the duration of the thread. |
| static constexpr size_t kMaxThreadNameLength = 32; |
| |
| struct ThreadMetrics : public app::Clusters::SoftwareDiagnostics::Structs::ThreadMetrics::Type |
| { |
| char NameBuf[kMaxThreadNameLength + 1]; |
| ThreadMetrics * Next; /* Pointer to the next structure. */ |
| }; |
| |
| class PlatformManager; |
| |
| /** |
| * Defines the delegate class of Platform Manager to notify platform updates. |
| */ |
| class PlatformManagerDelegate |
| { |
| public: |
| virtual ~PlatformManagerDelegate() {} |
| |
| /** |
| * @brief |
| * Called after the current device is rebooted |
| */ |
| virtual void OnDeviceRebooted() {} |
| }; |
| |
| /** |
| * Provides features for initializing and interacting with the chip network |
| * stack on a chip-enabled device. |
| */ |
| class PlatformManager |
| { |
| using ImplClass = ::chip::DeviceLayer::PlatformManagerImpl; |
| |
| public: |
| // ===== Members that define the public interface of the PlatformManager |
| |
| typedef void (*EventHandlerFunct)(const ChipDeviceEvent * event, intptr_t arg); |
| |
| /** |
| * InitChipStack() initializes the PlatformManager. After calling that, a |
| * consumer is allowed to call either StartEventLoopTask or RunEventLoop to |
| * process pending work. Calling both is not allowed: it must be one or the |
| * other. |
| */ |
| CHIP_ERROR InitChipStack(); |
| CHIP_ERROR AddEventHandler(EventHandlerFunct handler, intptr_t arg = 0); |
| void RemoveEventHandler(EventHandlerFunct handler, intptr_t arg = 0); |
| void SetDelegate(PlatformManagerDelegate * delegate) { mDelegate = delegate; } |
| PlatformManagerDelegate * GetDelegate() const { return mDelegate; } |
| |
| /** |
| * ScheduleWork can be called after InitChipStack has been called. Calls |
| * that happen before either StartEventLoopTask or RunEventLoop will queue |
| * the work up but that work will NOT run until one of those functions is |
| * called. |
| * |
| * ScheduleWork can be called safely on any thread without locking the |
| * stack. When called from a thread that is not doing the stack work item |
| * processing, the callback function may be called (on the work item |
| * processing thread) before ScheduleWork returns. |
| */ |
| void ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg = 0); |
| |
| /** |
| * Process work items until StopEventLoopTask is called. RunEventLoop will |
| * not return until work item processing is stopped. Once it returns it |
| * guarantees that no more work items will be processed unless there's |
| * another call to RunEventLoop. |
| * |
| * Consumers that call RunEventLoop must not call StartEventLoopTask. |
| * |
| * Consumers that call RunEventLoop must ensure that RunEventLoop returns |
| * before calling Shutdown. |
| */ |
| void RunEventLoop(); |
| |
| /** |
| * Process work items until StopEventLoopTask is called. |
| * |
| * StartEventLoopTask processes items asynchronously. It can return before |
| * any items are processed, or after some items have been processed, or |
| * while an item is being processed, or even after StopEventLoopTask() has |
| * been called (e.g. if ScheduleWork() was called before StartEventLoopTask |
| * was called, with a work item that calls StopEventLoopTask). |
| * |
| * Consumers that call StartEventLoopTask must not call RunEventLoop. |
| * |
| * Consumers that call StartEventLoopTask must ensure that they call |
| * StopEventLoopTask before calling Shutdown. |
| */ |
| CHIP_ERROR StartEventLoopTask(); |
| |
| /** |
| * Stop processing of work items by the event loop. |
| * |
| * If called from outside work item processing, StopEventLoopTask guarantees |
| * that any currently-executing work item completes execution and no more |
| * work items will run after StopEventLoopTask returns. This is generally |
| * how StopEventLoopTask is used in conjunction with StartEventLoopTask. |
| * |
| * If called from inside work item processing, StopEventLoopTask makes no |
| * guarantees about exactly when work item processing will stop. What it |
| * does guarantee is that if it is used this way in conjunction with |
| * RunEventLoop then all work item processing will stop before RunEventLoop |
| * returns. |
| */ |
| CHIP_ERROR StopEventLoopTask(); |
| void LockChipStack(); |
| bool TryLockChipStack(); |
| void UnlockChipStack(); |
| CHIP_ERROR Shutdown(); |
| |
| /** |
| * Software Diagnostics methods. |
| */ |
| CHIP_ERROR GetCurrentHeapFree(uint64_t & currentHeapFree); |
| CHIP_ERROR GetCurrentHeapUsed(uint64_t & currentHeapUsed); |
| CHIP_ERROR GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark); |
| |
| /* |
| * Get the linked list of thread metrics of the current plaform. After usage, each caller of GetThreadMetrics |
| * needs to release the thread metrics list it gets via ReleaseThreadMetrics. |
| * |
| */ |
| CHIP_ERROR GetThreadMetrics(ThreadMetrics ** threadMetricsOut); |
| void ReleaseThreadMetrics(ThreadMetrics * threadMetrics); |
| |
| /** |
| * General Diagnostics methods. |
| */ |
| CHIP_ERROR GetRebootCount(uint16_t & rebootCount); |
| CHIP_ERROR GetUpTime(uint64_t & upTime); |
| CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours); |
| CHIP_ERROR GetBootReasons(uint8_t & bootReasons); |
| |
| #if CHIP_STACK_LOCK_TRACKING_ENABLED |
| bool IsChipStackLockedByCurrentThread() const; |
| #endif |
| |
| private: |
| bool mInitialized = false; |
| PlatformManagerDelegate * mDelegate = nullptr; |
| |
| // ===== Members for internal use by the following friends. |
| |
| friend class PlatformManagerImpl; |
| friend class ConnectivityManagerImpl; |
| friend class ConfigurationManagerImpl; |
| friend class Dnssd::DiscoveryImplPlatform; |
| friend class TraitManager; |
| friend class ThreadStackManagerImpl; |
| friend class TimeSyncManager; |
| friend class Internal::DeviceControlServer; |
| friend class Internal::FabricProvisioningServer; |
| friend class Internal::ServiceProvisioningServer; |
| friend class Internal::BLEManagerImpl; |
| template <class> |
| friend class Internal::GenericPlatformManagerImpl; |
| template <class> |
| friend class Internal::GenericPlatformManagerImpl_FreeRTOS; |
| template <class> |
| friend class Internal::GenericPlatformManagerImpl_POSIX; |
| template <class> |
| friend class Internal::GenericPlatformManagerImpl_Zephyr; |
| template <class> |
| friend class Internal::GenericConnectivityManagerImpl_Thread; |
| template <class> |
| friend class Internal::GenericThreadStackManagerImpl_OpenThread; |
| template <class> |
| friend class Internal::GenericThreadStackManagerImpl_OpenThread_LwIP; |
| template <class> |
| friend class Internal::GenericConfigurationManagerImpl; |
| friend class System::PlatformEventing; |
| |
| /* |
| * PostEvent can be called safely on any thread without locking the stack. |
| * When called from a thread that is not doing the stack work item |
| * processing, the event might get dispatched (on the work item processing |
| * thread) before PostEvent returns. |
| */ |
| [[nodiscard]] CHIP_ERROR PostEvent(const ChipDeviceEvent * event); |
| void PostEventOrDie(const ChipDeviceEvent * event); |
| void DispatchEvent(const ChipDeviceEvent * event); |
| CHIP_ERROR StartChipTimer(System::Clock::Timeout duration); |
| |
| protected: |
| // Construction/destruction limited to subclasses. |
| PlatformManager() = default; |
| ~PlatformManager() = default; |
| |
| // No copy, move or assignment. |
| PlatformManager(const PlatformManager &) = delete; |
| PlatformManager(const PlatformManager &&) = delete; |
| PlatformManager & operator=(const PlatformManager &) = delete; |
| }; |
| |
| /** |
| * Returns the public interface of the PlatformManager singleton object. |
| * |
| * chip applications should use this to access features of the PlatformManager object |
| * that are common to all platforms. |
| */ |
| extern PlatformManager & PlatformMgr(); |
| |
| /** |
| * Returns the platform-specific implementation of the PlatformManager singleton object. |
| * |
| * chip applications can use this to gain access to features of the PlatformManager |
| * that are specific to the selected platform. |
| */ |
| extern PlatformManagerImpl & PlatformMgrImpl(); |
| |
| /** |
| * @brief |
| * RAII locking for PlatformManager to simplify management of |
| * LockChipStack()/UnlockChipStack calls. |
| */ |
| class StackLock |
| { |
| public: |
| StackLock() { PlatformMgr().LockChipStack(); } |
| |
| ~StackLock() { PlatformMgr().UnlockChipStack(); } |
| }; |
| |
| /** |
| * @brief |
| * RAII unlocking for PlatformManager to simplify management of |
| * LockChipStack()/UnlockChipStack calls. |
| */ |
| class StackUnlock |
| { |
| public: |
| StackUnlock() { PlatformMgr().UnlockChipStack(); } |
| ~StackUnlock() { PlatformMgr().LockChipStack(); } |
| }; |
| |
| } // namespace DeviceLayer |
| } // namespace chip |
| |
| /* Include a header file containing the implementation of the ConfigurationManager |
| * object for the selected platform. |
| */ |
| #ifdef EXTERNAL_PLATFORMMANAGERIMPL_HEADER |
| #include EXTERNAL_PLATFORMMANAGERIMPL_HEADER |
| #elif defined(CHIP_DEVICE_LAYER_TARGET) |
| #define PLATFORMMANAGERIMPL_HEADER <platform/CHIP_DEVICE_LAYER_TARGET/PlatformManagerImpl.h> |
| #include PLATFORMMANAGERIMPL_HEADER |
| #endif // defined(CHIP_DEVICE_LAYER_TARGET) |
| |
| namespace chip { |
| namespace DeviceLayer { |
| |
| #if CHIP_STACK_LOCK_TRACKING_ENABLED |
| inline bool PlatformManager::IsChipStackLockedByCurrentThread() const |
| { |
| return static_cast<const ImplClass *>(this)->_IsChipStackLockedByCurrentThread(); |
| } |
| #endif |
| |
| inline CHIP_ERROR PlatformManager::InitChipStack() |
| { |
| // NOTE: this is NOT thread safe and cannot be as the chip stack lock is prepared by |
| // InitChipStack itself on many platforms. |
| // |
| // In the future, this could be moved into specific platform code (where it can |
| // be made thread safe). In general however, init twice |
| // is likely a logic error and we may want to avoid that path anyway. Likely to |
| // be done once code stabilizes a bit more. |
| if (mInitialized) |
| { |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR err = static_cast<ImplClass *>(this)->_InitChipStack(); |
| mInitialized = (err == CHIP_NO_ERROR); |
| return err; |
| } |
| |
| inline CHIP_ERROR PlatformManager::AddEventHandler(EventHandlerFunct handler, intptr_t arg) |
| { |
| return static_cast<ImplClass *>(this)->_AddEventHandler(handler, arg); |
| } |
| |
| inline void PlatformManager::RemoveEventHandler(EventHandlerFunct handler, intptr_t arg) |
| { |
| static_cast<ImplClass *>(this)->_RemoveEventHandler(handler, arg); |
| } |
| |
| inline void PlatformManager::ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg) |
| { |
| static_cast<ImplClass *>(this)->_ScheduleWork(workFunct, arg); |
| } |
| |
| inline void PlatformManager::RunEventLoop() |
| { |
| static_cast<ImplClass *>(this)->_RunEventLoop(); |
| } |
| |
| /** |
| * @brief |
| * Starts the stack on its own task with an associated event queue |
| * to dispatch and handle events posted to that task. |
| * |
| * This is thread-safe. |
| * This is *NOT SAFE* to call from within the CHIP event loop since it can grab the stack lock. |
| */ |
| inline CHIP_ERROR PlatformManager::StartEventLoopTask() |
| { |
| return static_cast<ImplClass *>(this)->_StartEventLoopTask(); |
| } |
| |
| /** |
| * @brief |
| * This will trigger the event loop to exit and block till it has exited the loop. |
| * This prevents the processing of any further events in the queue. |
| * |
| * Additionally, this stops the CHIP task if the following criteria are met: |
| * 1. One was created earlier through a call to StartEventLoopTask |
| * 2. This call isn't being made from that task. |
| * |
| * This is safe to call from any task. |
| * This is safe to call from within the CHIP event loop. |
| * |
| */ |
| inline CHIP_ERROR PlatformManager::StopEventLoopTask() |
| { |
| return static_cast<ImplClass *>(this)->_StopEventLoopTask(); |
| } |
| |
| /** |
| * @brief |
| * Shuts down and cleans up the main objects in the CHIP stack. |
| * This DOES NOT stop the chip thread or event queue from running. |
| * |
| */ |
| inline CHIP_ERROR PlatformManager::Shutdown() |
| { |
| CHIP_ERROR err = static_cast<ImplClass *>(this)->_Shutdown(); |
| if (err == CHIP_NO_ERROR) |
| mInitialized = false; |
| return err; |
| } |
| |
| inline void PlatformManager::LockChipStack() |
| { |
| static_cast<ImplClass *>(this)->_LockChipStack(); |
| } |
| |
| inline bool PlatformManager::TryLockChipStack() |
| { |
| return static_cast<ImplClass *>(this)->_TryLockChipStack(); |
| } |
| |
| inline void PlatformManager::UnlockChipStack() |
| { |
| static_cast<ImplClass *>(this)->_UnlockChipStack(); |
| } |
| |
| inline CHIP_ERROR PlatformManager::PostEvent(const ChipDeviceEvent * event) |
| { |
| return static_cast<ImplClass *>(this)->_PostEvent(event); |
| } |
| |
| inline void PlatformManager::PostEventOrDie(const ChipDeviceEvent * event) |
| { |
| CHIP_ERROR status = static_cast<ImplClass *>(this)->_PostEvent(event); |
| VerifyOrDieWithMsg(status == CHIP_NO_ERROR, DeviceLayer, "Failed to post event %d: %" CHIP_ERROR_FORMAT, |
| static_cast<int>(event->Type), status.Format()); |
| } |
| |
| inline void PlatformManager::DispatchEvent(const ChipDeviceEvent * event) |
| { |
| static_cast<ImplClass *>(this)->_DispatchEvent(event); |
| } |
| |
| inline CHIP_ERROR PlatformManager::StartChipTimer(System::Clock::Timeout duration) |
| { |
| return static_cast<ImplClass *>(this)->_StartChipTimer(duration); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetCurrentHeapFree(uint64_t & currentHeapFree) |
| { |
| return static_cast<ImplClass *>(this)->_GetCurrentHeapFree(currentHeapFree); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetCurrentHeapUsed(uint64_t & currentHeapUsed) |
| { |
| return static_cast<ImplClass *>(this)->_GetCurrentHeapUsed(currentHeapUsed); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) |
| { |
| return static_cast<ImplClass *>(this)->_GetCurrentHeapHighWatermark(currentHeapHighWatermark); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetThreadMetrics(ThreadMetrics ** threadMetricsOut) |
| { |
| return static_cast<ImplClass *>(this)->_GetThreadMetrics(threadMetricsOut); |
| } |
| |
| inline void PlatformManager::ReleaseThreadMetrics(ThreadMetrics * threadMetrics) |
| { |
| return static_cast<ImplClass *>(this)->_ReleaseThreadMetrics(threadMetrics); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetRebootCount(uint16_t & rebootCount) |
| { |
| return static_cast<ImplClass *>(this)->_GetRebootCount(rebootCount); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetUpTime(uint64_t & upTime) |
| { |
| return static_cast<ImplClass *>(this)->_GetUpTime(upTime); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetTotalOperationalHours(uint32_t & totalOperationalHours) |
| { |
| return static_cast<ImplClass *>(this)->_GetTotalOperationalHours(totalOperationalHours); |
| } |
| |
| inline CHIP_ERROR PlatformManager::GetBootReasons(uint8_t & bootReasons) |
| { |
| return static_cast<ImplClass *>(this)->_GetBootReasons(bootReasons); |
| } |
| |
| } // namespace DeviceLayer |
| } // namespace chip |