/* * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "sdkconfig.h" #include "freertos/idf_additions.h" #if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT #include "freertos/task_snapshot.h" #endif /* CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT */ #include "esp_private/freertos_idf_additions_priv.h" /** * This file will be included in `tasks.c` file, thus, it is treated as a source * file instead of a header file, and must NOT be included by any (other) file. * This file is used to add additional functions to `tasks.c`. See the * `esp_additions/include` directory of the headers that expose these `tasks.c` * additional API. */ /* ------------------------------------------------- Static Asserts ------------------------------------------------- */ /** * Both StaticTask_t and TCB_t structures are provided by FreeRTOS sources. * This is just an additional check of the consistency of these structures. */ _Static_assert( offsetof( StaticTask_t, pxDummy6 ) == offsetof( TCB_t, pxStack ) ); _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfStack ) ); #if CONFIG_FREERTOS_SMP _Static_assert( tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "CONFIG_FREERTOS_NO_AFFINITY must be the same as tskNO_AFFINITY" ); #endif /* CONFIG_FREERTOS_SMP */ /* -------------------------------------------------- Task Creation ------------------------------------------------- */ #if CONFIG_FREERTOS_SMP BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, const BaseType_t xCoreID ) { BaseType_t ret; #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) { /* Convert xCoreID into an affinity mask */ UBaseType_t uxCoreAffinityMask; if( xCoreID == tskNO_AFFINITY ) { uxCoreAffinityMask = tskNO_AFFINITY; } else { uxCoreAffinityMask = ( 1 << xCoreID ); } ret = xTaskCreateAffinitySet( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask ); } #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ { ret = xTaskCreate( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); } #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ return ret; } #endif /* CONFIG_FREERTOS_SMP */ /*----------------------------------------------------------*/ #if ( CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer, const BaseType_t xCoreID ) { TaskHandle_t ret; #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) { /* Convert xCoreID into an affinity mask */ UBaseType_t uxCoreAffinityMask; if( xCoreID == tskNO_AFFINITY ) { uxCoreAffinityMask = tskNO_AFFINITY; } else { uxCoreAffinityMask = ( 1 << xCoreID ); } ret = xTaskCreateStaticAffinitySet( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask ); } #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ { ret = xTaskCreateStatic( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer ); } #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */ return ret; } #endif /* CONFIG_FREERTOS_SMP && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ /*----------------------------------------------------------*/ /* ------------------------------------------------- Task Utilities ------------------------------------------------- */ #if CONFIG_FREERTOS_SMP TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ) { TaskHandle_t xTaskHandleTemp; assert( xCoreID >= 0 && xCoreID < configNUM_CORES ); taskENTER_CRITICAL(); xTaskHandleTemp = ( TaskHandle_t ) pxCurrentTCBs[ xCoreID ]; taskEXIT_CRITICAL(); return xTaskHandleTemp; } #endif /* CONFIG_FREERTOS_SMP */ /*----------------------------------------------------------*/ #if CONFIG_FREERTOS_SMP TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ) { assert( xCoreID >= 0 && xCoreID < configNUM_CORES ); return ( TaskHandle_t ) xIdleTaskHandle[ xCoreID ]; } #endif /* CONFIG_FREERTOS_SMP */ /*----------------------------------------------------------*/ #if CONFIG_FREERTOS_SMP BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) { taskENTER_CRITICAL(); UBaseType_t uxCoreAffinityMask; #if ( configUSE_CORE_AFFINITY == 1 && configNUM_CORES > 1 ) TCB_t * pxTCB = prvGetTCBFromHandle( xTask ); uxCoreAffinityMask = pxTCB->uxCoreAffinityMask; #else uxCoreAffinityMask = tskNO_AFFINITY; #endif taskEXIT_CRITICAL(); BaseType_t ret; /* If the task is not pinned to a particular core, treat it as tskNO_AFFINITY */ if( uxCoreAffinityMask & ( uxCoreAffinityMask - 1 ) ) /* If more than one bit set */ { ret = tskNO_AFFINITY; } else { int index_plus_one = __builtin_ffs( uxCoreAffinityMask ); assert( index_plus_one >= 1 ); ret = index_plus_one - 1; } return ret; } #endif /* CONFIG_FREERTOS_SMP */ /*----------------------------------------------------------*/ #if ( INCLUDE_vTaskPrioritySet == 1 ) void prvTaskPriorityRaise( prvTaskSavedPriority_t * pxSavedPriority, UBaseType_t uxNewPriority ) { TCB_t * pxTCB; UBaseType_t uxPriorityUsedOnEntry; configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); /* Ensure the new priority is valid. */ if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) { uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; } #if CONFIG_FREERTOS_SMP taskENTER_CRITICAL(); #else taskENTER_CRITICAL( &xKernelLock ); #endif { pxTCB = prvGetTCBFromHandle( NULL ); #if ( configUSE_MUTEXES == 1 ) { pxSavedPriority->uxPriority = pxTCB->uxPriority; pxSavedPriority->uxBasePriority = pxTCB->uxBasePriority; /* If uxNewPriority < uxBasePriority, then there is nothing else to * do, as uxBasePriority is always <= uxPriority. */ if( uxNewPriority > pxTCB->uxBasePriority ) { pxTCB->uxBasePriority = uxNewPriority; /* Remember the task's current priority before attempting to * change it. If the task's current priority is changed, it must * be done so before moving the task between task lists) in order * for the taskRESET_READY_PRIORITY() macro to function correctly. */ uxPriorityUsedOnEntry = pxTCB->uxPriority; if( uxNewPriority > pxTCB->uxPriority ) { pxTCB->uxPriority = uxNewPriority; /* Only reset the event list item value if the value is not * being used for anything else. */ if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } /* If the task is in the blocked or suspended list we need do * nothing more than change its priority variable. However, if * the task is in a ready list it needs to be removed and placed * in the list appropriate to its new priority. */ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) { /* The task is currently in its ready list - remove before * adding it to its new ready list. As we are in a critical * section we can do this even if the scheduler is suspended. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { /* It is known that the task is in its ready list so * there is no need to check again and the port level * reset macro can be called directly. */ portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); } prvAddTaskToReadyList( pxTCB ); } } } } #else /* if ( configUSE_MUTEXES == 1 ) */ { pxSavedPriority->uxPriority = pxTCB->uxPriority; if( uxNewPriority > pxTCB->uxPriority ) { vTaskPrioritySet( NULL, uxNewPriority ); } } #endif /* if ( configUSE_MUTEXES == 1 ) */ } #if CONFIG_FREERTOS_SMP taskEXIT_CRITICAL(); #else taskEXIT_CRITICAL( &xKernelLock ); #endif } #endif /* INCLUDE_vTaskPrioritySet == 1 */ /*----------------------------------------------------------*/ #if ( INCLUDE_vTaskPrioritySet == 1 ) void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority ) { TCB_t * pxTCB; UBaseType_t uxNewPriority; UBaseType_t uxPriorityUsedOnEntry; UBaseType_t uxBasePriorityUsedOnEntry; BaseType_t xYieldRequired = pdFALSE; #if CONFIG_FREERTOS_SMP taskENTER_CRITICAL(); #else taskENTER_CRITICAL( &xKernelLock ); #endif { pxTCB = prvGetTCBFromHandle( NULL ); #if ( configUSE_MUTEXES == 1 ) { /* If the saved uxBasePriority == the task's uxBasePriority, it means * that prvTaskPriorityRaise() never raised the task's uxBasePriority. * In that case, there is nothing else to do. */ if( pxSavedPriority->uxBasePriority != pxTCB->uxBasePriority ) { uxBasePriorityUsedOnEntry = pxTCB->uxBasePriority; pxTCB->uxBasePriority = pxSavedPriority->uxBasePriority; /* Remember the task's current priority before attempting to * change it. If the task's current priority is changed, it must * be done so before moving the task between task lists in order * for the taskRESET_READY_PRIORITY() macro to function correctly. */ uxPriorityUsedOnEntry = pxTCB->uxPriority; /* Check if the task inherited a priority after prvTaskPriorityRaise(). * If this is the case, there is nothing else to do. The priority * will be restored when the task disinherits its priority. */ if( pxTCB->uxPriority == uxBasePriorityUsedOnEntry ) { if( pxTCB->uxMutexesHeld == 0 ) { /* The task may have inherited a priority before prvTaskPriorityRaise() * then disinherited a priority after prvTaskPriorityRaise(). * Thus we need set the uxPriority to the saved base priority * so that the task's priority gets restored to the priority * before any inheritance or raising. */ pxTCB->uxPriority = pxSavedPriority->uxBasePriority; } else { /* The task may have inherited a priority before prvTaskPriorityRaise() * was called. Thus, we need to restore uxPriority to the * "saved uxPriority" so that the task still retains that * inherited priority. */ pxTCB->uxPriority = pxSavedPriority->uxPriority; } uxNewPriority = pxTCB->uxPriority; if( uxNewPriority < uxPriorityUsedOnEntry ) { /* Setting the priority of the running task down means * there may now be another task of higher priority that * is ready to execute. */ xYieldRequired = pdTRUE; } /* Only reset the event list item value if the value is not * being used for anything else. */ if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } /* If the task is in the blocked or suspended list we need do * nothing more than change its priority variable. However, if * the task is in a ready list it needs to be removed and placed * in the list appropriate to its new priority. */ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) { /* The task is currently in its ready list - remove before * adding it to its new ready list. As we are in a critical * section we can do this even if the scheduler is suspended. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { /* It is known that the task is in its ready list so * there is no need to check again and the port level * reset macro can be called directly. */ portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); } prvAddTaskToReadyList( pxTCB ); } if( xYieldRequired != pdFALSE ) { taskYIELD_IF_USING_PREEMPTION(); } } } } #else /* if ( configUSE_MUTEXES == 1 ) */ { vTaskPrioritySet( NULL, pxSavedPriority->uxPriority ); } #endif /* if ( configUSE_MUTEXES == 1 ) */ } #if CONFIG_FREERTOS_SMP taskEXIT_CRITICAL(); #else taskEXIT_CRITICAL( &xKernelLock ); #endif } #endif /* ( INCLUDE_vTaskPrioritySet == 1 ) */ /*----------------------------------------------------------*/ /* --------------------------------------------- TLSP Deletion Callbacks -------------------------------------------- */ #if ( CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void * pvValue, TlsDeleteCallbackFunction_t pvDelCallback ) { /* Verify that the offsets of pvThreadLocalStoragePointers and pvDummy15 match. */ /* pvDummy15 is part of the StaticTask_t struct and is used to access the TLSPs */ /* while deletion. */ _Static_assert( offsetof( StaticTask_t, pvDummy15 ) == offsetof( TCB_t, pvThreadLocalStoragePointers ), "Offset of pvDummy15 must match the offset of pvThreadLocalStoragePointers" ); /*Set the local storage pointer first */ vTaskSetThreadLocalStoragePointer( xTaskToSet, xIndex, pvValue ); /*Set the deletion callback at an offset of configNUM_THREAD_LOCAL_STORAGE_POINTERS/2 */ vTaskSetThreadLocalStoragePointer( xTaskToSet, ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ), pvDelCallback ); } #endif /* CONFIG_FREERTOS_SMP && CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ /*----------------------------------------------------------*/ /* ----------------------------------------------------- Newlib ----------------------------------------------------- */ #if ( configUSE_NEWLIB_REENTRANT == 1 ) /** * @brief Get reentrancy structure of the current task * * - This funciton is required by newlib (when __DYNAMIC_REENT__ is enabled) * - It will return a pointer to the current task's reent struct * - If FreeRTOS is not running, it will return the global reent struct * * @return Pointer to a the (current taks's)/(globa) reent struct */ struct _reent * __getreent( void ) { /* No lock needed because if this changes, we won't be running anymore. */ TCB_t * pxCurTask = xTaskGetCurrentTaskHandle(); struct _reent * ret; if( pxCurTask == NULL ) { /* No task running. Return global struct. */ ret = _GLOBAL_REENT; } else { /* We have a task; return its reentrant struct. */ ret = &pxCurTask->xNewLib_reent; } return ret; } #endif /* configUSE_NEWLIB_REENTRANT == 1 */ /* -------------------------------------------------- Task Snapshot ------------------------------------------------- */ /** * @brief List of all task lists in FreeRTOS * * @note There are currently differing number of task list between SMP FreeRTOS and ESP-IDF FreeRTOS */ static List_t * non_ready_task_lists[] = { #ifdef CONFIG_FREERTOS_SMP &xPendingReadyList, #else /* CONFIG_FREERTOS_SMP */ &xPendingReadyList[ 0 ], #ifndef CONFIG_FREERTOS_UNICORE &xPendingReadyList[ 1 ], #endif /* CONFIG_FREERTOS_UNICORE */ #endif /* CONFIG_FREERTOS_SMP */ &xDelayedTaskList1, &xDelayedTaskList2, #if ( INCLUDE_vTaskDelete == 1 ) &xTasksWaitingTermination, #endif #if ( INCLUDE_vTaskSuspend == 1 ) &xSuspendedTaskList, #endif }; /*----------------------------------------------------------*/ /** * @brief Get the next task list to traverse * * - Given a particular task list, this function returns the next task to traverse. * - The task lists are returned in the following precedence * - Ready lists (highest to lowers priority) * - Pending ready list(s) * - Delayed list 1 * - Delayed list 2 * - Waiting termination list * - Suspended list * * @param pxCurTaskList Previously traversed task list (or NULL if obtaining the first task list) * @return List_t* The next task list to traverse (or NULL of all task lists have been traversed) */ static List_t * pxGetNextTaskList( List_t * pxCurTaskList ) { List_t * pxNextTaskList = NULL; /* No Current List. Start from the highest priority ready task list */ if( pxCurTaskList == NULL ) { pxNextTaskList = &pxReadyTasksLists[ configMAX_PRIORITIES - 1 ]; } /* Current list is one of the ready task lists. Find the current priority, and return the next lower priority ready task list */ else if( ( pxCurTaskList >= &pxReadyTasksLists[ 0 ] ) && ( pxCurTaskList <= &pxReadyTasksLists[ configMAX_PRIORITIES - 1 ] ) ) { /* Find the current priority */ int cur_priority; for( cur_priority = configMAX_PRIORITIES - 1; cur_priority >= 0; cur_priority-- ) { if( pxCurTaskList == &pxReadyTasksLists[ cur_priority ] ) { break; } } /* Return the ready task list at (cur_priority - 1), or the pending ready task list */ if( cur_priority > 0 ) { pxNextTaskList = &pxReadyTasksLists[ cur_priority - 1 ]; } /* We've reached the end of the Ready Task Lists. We get the next list from the non-ready task lists */ else if( cur_priority == 0 ) { pxNextTaskList = non_ready_task_lists[ 0 ]; } else { abort(); /* This should never occur */ } } /* Current list is one of the non-ready task lists. Fetch the next non-ready task list */ if( pxNextTaskList == NULL ) { int cur_list_idx; const int num_non_ready_task_lists = ( sizeof( non_ready_task_lists ) / sizeof( List_t * ) ); /* Note: - 1 so that if the current list is the last on non_ready_task_lists[], the next list will return NULL */ for( cur_list_idx = 0; cur_list_idx < num_non_ready_task_lists - 1; cur_list_idx++ ) { if( pxCurTaskList == non_ready_task_lists[ cur_list_idx ] ) { pxNextTaskList = non_ready_task_lists[ cur_list_idx + 1 ]; break; } } } return pxNextTaskList; } /*----------------------------------------------------------*/ TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask ) { TCB_t * pxTCB = ( TCB_t * ) pxTask; /* Check current task is valid */ if( ( pxTCB != NULL ) && !portVALID_TCB_MEM( pxTCB ) ) { return NULL; } List_t * pxCurTaskList; const ListItem_t * pxCurListItem; if( pxTCB == NULL ) { /* Starting traversal for the first time */ pxCurTaskList = pxGetNextTaskList( NULL ); pxCurListItem = listGET_END_MARKER( pxCurTaskList ); } else { /* Continuing traversal */ pxCurTaskList = listLIST_ITEM_CONTAINER( &pxTCB->xStateListItem ); pxCurListItem = &pxTCB->xStateListItem; } ListItem_t * pxNextListItem = NULL; if( pxCurListItem->pxNext == listGET_END_MARKER( pxCurTaskList ) ) { List_t * pxNextTaskList = pxGetNextTaskList( pxCurTaskList ); while( pxNextTaskList != NULL ) { if( !listLIST_IS_EMPTY( pxNextTaskList ) ) { /* Get the first item in the next task list */ pxNextListItem = listGET_HEAD_ENTRY( pxNextTaskList ); break; } /* Task list is empty. Get the next task list */ pxNextTaskList = pxGetNextTaskList( pxNextTaskList ); } } else { /*There are still more items in the current task list. Get the next item */ pxNextListItem = listGET_NEXT( pxCurListItem ); } TCB_t * pxNextTCB; if( pxNextListItem == NULL ) { pxNextTCB = NULL; } else { pxNextTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxNextListItem ); } return pxNextTCB; } /*----------------------------------------------------------*/ BaseType_t vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t * pxTaskSnapshot ) { if( ( portVALID_TCB_MEM( pxTask ) == false ) || ( pxTaskSnapshot == NULL ) ) { return pdFALSE; } TCB_t * pxTCB = ( TCB_t * ) pxTask; pxTaskSnapshot->pxTCB = pxTCB; pxTaskSnapshot->pxTopOfStack = ( StackType_t * ) pxTCB->pxTopOfStack; pxTaskSnapshot->pxEndOfStack = ( StackType_t * ) pxTCB->pxEndOfStack; return pdTRUE; } /*----------------------------------------------------------*/ UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArrayLength, UBaseType_t * const pxTCBSize ) { UBaseType_t uxArrayNumFilled = 0; /*Traverse all of the tasks lists */ List_t * pxCurTaskList = pxGetNextTaskList( NULL ); /*Get the first task list */ while( pxCurTaskList != NULL && uxArrayNumFilled < uxArrayLength ) { if( !listLIST_IS_EMPTY( pxCurTaskList ) ) { const ListItem_t * pxCurListItem; /*Walk each task on the current task list */ pxCurListItem = listGET_HEAD_ENTRY( pxCurTaskList ); while( pxCurListItem != listGET_END_MARKER( pxCurTaskList ) ) { TCB_t * pxTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxCurListItem ); vTaskGetSnapshot( ( TaskHandle_t ) pxTCB, &pxTaskSnapshotArray[ uxArrayNumFilled ] ); uxArrayNumFilled++; if( !( uxArrayNumFilled < uxArrayLength ) ) { break; } pxCurListItem = listGET_NEXT( pxCurListItem ); } } /*Get the next task list */ pxCurTaskList = pxGetNextTaskList( pxCurTaskList ); } *pxTCBSize = sizeof( TCB_t ); return uxArrayNumFilled; } /*----------------------------------------------------------*/ /* ----------------------------------------------------- OpenOCD ---------------------------------------------------- */ #if CONFIG_FREERTOS_DEBUG_OCDAWARE /** * Debug param indexes. DO NOT change the order. OpenOCD uses the same indexes * Entries in FreeRTOS_openocd_params must match the order of these indexes */ enum { ESP_FREERTOS_DEBUG_TABLE_SIZE = 0, ESP_FREERTOS_DEBUG_TABLE_VERSION, ESP_FREERTOS_DEBUG_KERNEL_VER_MAJOR, ESP_FREERTOS_DEBUG_KERNEL_VER_MINOR, ESP_FREERTOS_DEBUG_KERNEL_VER_BUILD, ESP_FREERTOS_DEBUG_UX_TOP_USED_PIORITY, ESP_FREERTOS_DEBUG_PX_TOP_OF_STACK, ESP_FREERTOS_DEBUG_PC_TASK_NAME, /* New entries must be inserted here */ ESP_FREERTOS_DEBUG_TABLE_END, }; const DRAM_ATTR uint8_t FreeRTOS_openocd_params[ ESP_FREERTOS_DEBUG_TABLE_END ] = { ESP_FREERTOS_DEBUG_TABLE_END, /* table size */ 1, /* table version */ tskKERNEL_VERSION_MAJOR, tskKERNEL_VERSION_MINOR, tskKERNEL_VERSION_BUILD, configMAX_PRIORITIES - 1, /* uxTopUsedPriority */ offsetof( TCB_t, pxTopOfStack ), /* thread_stack_offset; */ offsetof( TCB_t, pcTaskName ), /* thread_name_offset; */ }; #endif /* CONFIG_FREERTOS_DEBUG_OCDAWARE */ /*----------------------------------------------------------*/