/* * * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2019 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 * Provides an implementation of the ThreadStackManager object for * CC13XX_26XX platforms using the Texas Instruments SDK and the * OpenThread stack. * */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #include #include // platform folder in the TI SDK example application #include // DMM Includes #ifdef USE_DMM #include "ti_dmm_application_policy.h" #include #include #include #endif namespace chip { namespace DeviceLayer { using namespace ::chip::DeviceLayer::Internal; ThreadStackManagerImpl ThreadStackManagerImpl::sInstance; #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE != 0 static void * ot_calloc(size_t n, size_t size) { void * p_ptr = NULL; p_ptr = pvPortMalloc(n * size); memset(p_ptr, 0, n * size); return p_ptr; } static void ot_free(void * p_ptr) { vPortFree(p_ptr); } #endif /* OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE != 0 */ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack(void) { return InitThreadStack(NULL); } CHIP_ERROR ThreadStackManagerImpl::InitThreadStack(otInstance * otInst) { CHIP_ERROR err = CHIP_NO_ERROR; // Create FreeRTOS queue for platform driver messages procQueue = xQueueCreate(20U, sizeof(ThreadStackManagerImpl::procQueueMsg)); procQueue_radio = xQueueCreate(20U, sizeof(ThreadStackManagerImpl::procQueueMsg)); #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE != 0 mbedtls_platform_set_calloc_free(ot_calloc, ot_free); #endif /* OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE != 0 */ // Initialize the OpenThread platform layer platformAlarmInit(); platformAlarmMicroInit(); platformRandomInit(); platformRadioInit(); #ifdef USE_DMM // DMM Init DMMSch_registerClient(xTaskGetCurrentTaskHandle(), DMMPolicy_StackRole_threadFtd); DMMPolicy_updateStackState(DMMPolicy_StackRole_threadFtd, DMMPOLICY_THREAD_IDLE); #endif // Initialize the generic implementation base classes. err = GenericThreadStackManagerImpl_FreeRTOS::DoInit(); SuccessOrExit(err); err = GenericThreadStackManagerImpl_OpenThread_LwIP::DoInit(otInst); SuccessOrExit(err); exit: return err; } bool ThreadStackManagerImpl::IsInitialized() { return sInstance.mThreadStackLock != NULL; } void ThreadStackManagerImpl::_SendProcMessage(ThreadStackManagerImpl::procQueueMsg & procMsg) { BaseType_t err; if (procMsg.cmd == procQueueCmd_radio) { err = xQueueSendFromISR(procQueue_radio, &procMsg, NULL); } else { err = xQueueSendFromISR(procQueue, &procMsg, NULL); } (void) err; // signal processing loop SignalThreadActivityPendingFromISR(); } extern "C" void * otPlatCAlloc(size_t aNum, size_t aSize) { return chip::Platform::MemoryCalloc(aNum, aSize); } extern "C" void otPlatFree(void * aPtr) { if (aPtr != nullptr) { chip::Platform::MemoryFree(aPtr); } } void ThreadStackManagerImpl::_ProcMessage(otInstance * aInstance) { procQueueMsg procMsg; procQueueMsg procMsg_radio; /* Process Radio events */ while (pdTRUE == xQueueReceive(procQueue_radio, &procMsg_radio, 0U)) { switch (procMsg_radio.cmd) { case procQueueCmd_radio: { platformRadioProcess(aInstance, procMsg_radio.arg); break; } default: { break; } } } while (pdTRUE == xQueueReceive(procQueue, &procMsg, 0U)) { switch (procMsg.cmd) { case procQueueCmd_alarm: { platformAlarmProcess(aInstance); break; } case procQueueCmd_tasklets: { otTaskletsProcess(aInstance); break; } case procQueueCmd_alarmu: { platformAlarmMicroProcess(aInstance); break; } default: { break; } } } } void ThreadStackManagerImpl::GetExtAddress(otExtAddress & aExtAddr) { const otExtAddress * extAddr; LockThreadStack(); extAddr = otLinkGetExtendedAddress(OTInstance()); UnlockThreadStack(); memcpy(aExtAddr.m8, extAddr->m8, OT_EXT_ADDRESS_SIZE); } bool ThreadStackManagerImpl::IsThreadAttached() { return _IsThreadAttached(); } bool ThreadStackManagerImpl::IsThreadEnabled() { return _IsThreadEnabled(); } } // namespace DeviceLayer } // namespace chip using namespace ::chip::DeviceLayer; /** * Glue function called by alarm processing layer to notify OpenThread the driver needs processing. */ extern "C" void platformAlarmSignal() { ThreadStackManagerImpl::procQueueMsg msg; msg.cmd = ThreadStackManagerImpl::procQueueCmd_alarm; ThreadStackMgrImpl()._SendProcMessage(msg); } /** * Glue function called by alarm processing layer to notify OpenThread the driver needs processing. */ extern "C" void platformAlarmMicroSignal() { ThreadStackManagerImpl::procQueueMsg msg; msg.cmd = ThreadStackManagerImpl::procQueueCmd_alarmu; ThreadStackMgrImpl()._SendProcMessage(msg); } /** * Glue function called by radio processing layer to notify OpenThread the driver needs processing. */ extern "C" void platformRadioSignal(uintptr_t arg) { ThreadStackManagerImpl::procQueueMsg msg; msg.cmd = ThreadStackManagerImpl::procQueueCmd_radio; msg.arg = arg; ThreadStackMgrImpl()._SendProcMessage(msg); } /** * Glue function called directly by the OpenThread stack when tasklet processing work * is pending. */ extern "C" void otTaskletsSignalPending(otInstance * p_instance) { ThreadStackMgrImpl().SignalThreadActivityPending(); } /** * Process events from the drivers */ extern "C" void otSysProcessDrivers(otInstance * aInstance) { ThreadStackMgrImpl()._ProcMessage(aInstance); } /** * Get a pointer to the OpenThread instance object. * * @return Pointer to the OpenThread instance object. */ extern "C" otInstance * OtInstance_get(void) { return ThreadStackMgrImpl().OTInstance(); }