---
tags: 嵌入式作業系統分析與實作
---
# Lab3-Task_Monitor
contributed by <`RusselCK` >
###### tags: `RusselCK`
## 作業要求

給定下列 tasks,從 `pxReadyTasksLists` 或 `pxDelayedTaskList` 找出他們的 TCB ,並將其部分內容在 Console 呈現出來。
| Task Name | Priority |
|:----------------------- |:--------:|
| `Lab03_Red_LED` | 1 |
| `Lab03_Green_LED` | 1 |
| `Lab03_Delay_App` | 14 |
| `Lab03_TaskMonitor_App` | 2 |
## Pinout & Configuration




## UART & TTL
### UART
- [ ] [UART (Universal Asynchronous Receiver/Transmitter)](https://zh.wikipedia.org/wiki/UART)
Using an USART to USB dongle from the market connected for instance to STM32F407 USART2 available on connector P1 pin 14 (PA2: USART2_TX) and P1 pin 13 (PA3: USART2_RX).


### USBtoTTL


## `main.c`
```c
/* Private includes ----------------------------------------*/
/* USER CODE BEGIN Includes */
#include "FreeRTOS.h"
#include "task.h"
/* USER CODE END Includes */
```
### Lab03_Red_LED
```c
void Red_LED_App(void *pvParameters)
{
uint32_t Redtimer = 500;
while(1){
HAL_GPIO_TogglePin(GPIOD,Red_LED_Pin);
vTaskDelay(Redtimer);
Redtimer += 1;
}
}
```
### Lab03_Green_LED
```c
void Green_LED_App(void *pvParameters)
{
uint32_t Greentimer = 1000;
while(1){
HAL_GPIO_TogglePin(GPIOD,Green_LED_Pin);
vTaskDelay(Greentimer);
Greentimer += 2;
}
}
```
### Lab03_Delay_App
```c
void Delay_App(void *pvParameters)
{
while(1){
vTaskDelay(15000);
}
}
```
### Lab03_TaskMonitor_App
```c
void Taskmonitor(void);
void TaskMonitor_App(void *pvParameters)
{
uint8_t i = 100;
for(;;){
Taskmonitor();
i += 1;
vTaskDelay(i);
if( i == 500)
i = 0 ;
}
}
```
:::warning
Lab03 最重要的任務就是完成 `Taskmonitor()`
:::
### Lab03_start
```c
void vLab03_start (void *pvParameters)
{
xTaskCreate(Red_LED_App, "Lab03_Red_LED", 1000, NULL, 1, NULL);
xTaskCreate(Green_LED_App, "Lab03_Green_LED", 1000, NULL, 1, NULL);
xTaskCreate(Delay_App, "Lab03_Delay_App", 1000, NULL, 14, NULL);
xTaskCreate(TaskMonitor_App, "Lab03_TaskMonitor_App", 1000, NULL, 2, NULL);
vTaskDelete(NULL);
}
int main (void)
{
/* USER CODE BEGIN 2 */
xTaskCreate(vLab03_start, "Lab03_Start", 1000, NULL, 1, NULL);
vTaskStartScheduler();
/* USER CODE END 2 */
}
```
## TCB
### TCB 的位置
#### `pxReadyTaskLists[priority]`

每個 priority 會有一條 `pxReadyTaskList`
#### `pxDelayedTaskList`
`pxDelayedTaskList` 只有一條,且結構與 `pxReadyTaskList` 相同
### TCB 的結構
`task.c`
```c
typrdef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack;
UBaseType_t uxPriority
StackType_t * pxStack;
char pcTaskName[ configMAX_TASK_NAME_LEN ];
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority;
#endif
...
} tskTCB;
typedef tskTCB TCB_t
```
> 僅列出 Lab03 會用到的項目
## Lists Macro
`list.h`
```c
/* default */
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
/* add by your own */
#define listGET_ITEM_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext )
```
> 僅列出 Lab03 會用到的部分
**`listGET_OWNER_OF_HEAD_ENTRY( pxList )`** 會直接指向 List 的第一個 `xListItem` 的 TCB
* 這樣一來就無法進入 List 的第二個 `xListItem`
**`listGET_ITEM_OF_HEAD_ENTRY( pxList )`** 會指向 List 的一個 `xListItem`
* 可以保有去 TCB 或下一個 `xListItem` 的選擇彈性
## `task.c`
```c
#include <stdio.h>
#include "stm32f4xx_hal.h"
```
```c
UART_HandleTypeDef huart2; // for USART2
```
### `Uint32ConvertHex()`
```c
void Uint32ConvertHex(volatile StackType_t pStack, char *charTxScanTaskStack)
{
uint32_t remainder,quotient;
int index = 0;
quotient = pStack;
charTxScanTaskStack[index++] = 48; // ascii number 0
charTxScanTaskStack[index++] = 120; // ascii alphabet x
while (quotient != 0)
{
remainder = quotient & 0xf; // quotient % 16
if (remainder < 10)
charTxScanTaskStack[index++] = '0' + remainder;
else
charTxScanTaskStack[index++] = 55 + remainder; // A = 65;
quotient = quotient >> 4; // quotient / 16
}
/* reverse */
int end = index-1;
for(int reversal = 2;reversal <= end; ++reversal, --end)
{
charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal];
charTxScanTaskStack[reversal] ^= charTxScanTaskStack[end];
charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal];
}
charTxScanTaskStack[index++] = 0;
}
```
### `LongConvertCharArray()`
```c
void LongConvertCharArray(UBaseType_t TxScanTaskPriority, char *charTxScanTaskStack)
{
uint32_t remainder,quotient;
int index = 0;
quotient = TxScanTaskPriority;
if(quotient == 0)
charTxScanTaskStack[index++] = '0';
while (quotient != 0){
remainder = quotient % 10;
charTxScanTaskStack[index++] = '0' + remainder;
quotient = quotient / 10;
}
/* reverse */
if (index == 1) return;
int end = index-1;
for(int reversal = 0; reversal <= end; ++reversal, --end)
{
charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal];
charTxScanTaskStack[reversal] ^= charTxScanTaskStack[end];
charTxScanTaskStack[end] ^= charTxScanTaskStack[reversal];
}
charTxScanTaskStack[index++] = 0;
}
```
### `PrintTCBContext()`
**簡化版**
```c
void PrintTCBContext(TCB_t *taskTCB, char taskState[])
{
/* get TCB contexts */
char taskBasePriority[3]; memset(taskBasePriority,'\0',sizeof(taskBasePriority));
LongConvertCharArray(taskTCB->uxBasePriority, taskBasePriority);
char taskPriority[3]; memset(taskPriority,'\0',sizeof(taskPriority));
LongConvertCharArray(taskTCB->uxPriority, taskPriority);
char taskStack[11]; memset(taskStack,'\0',sizeof(taskStack));
Uint32ConvertHex(taskTCB->pxStack, taskStack);
char taskTOS[11]; memset(taskTOS,'\0',sizeof(taskTOS));
Uint32ConvertHex(taskTCB->pxTopOfStack, taskTOS);
/* ouput TCB contexts */
char Monitor[150]; memset(Monitor,'\0',sizeof(Monitor));
strcat(Monitor,taskTCB->pcTaskName);
int taskNamelen = strlen(taskTCB->pcTaskName);
strcat(Monitor,taskBasePriority);
strcat(Monitor,taskPriority);
strcat(Monitor,taskStack);
strcat(Monitor,taskTOS);
strcat(Monitor, taskState);
strcat(Monitor, "\n\r");
HAL_UART_Transmit(&huart2,(uint8_t *)Monitor,strlen(Monitor),0xffff);
}
```
**調整排版**
```c
void PrintTCBContext(TCB_t *taskTCB, char taskState[])
{
/* get TCB contexts */
char taskBasePriority[3]; memset(taskBasePriority,'\0',sizeof(taskBasePriority));
LongConvertCharArray(taskTCB->uxBasePriority, taskBasePriority);
char taskPriority[3]; memset(taskPriority,'\0',sizeof(taskPriority));
LongConvertCharArray(taskTCB->uxPriority, taskPriority);
char taskStack[11]; memset(taskStack,'\0',sizeof(taskStack));
Uint32ConvertHex(taskTCB->pxStack, taskStack);
char taskTOS[11]; memset(taskTOS,'\0',sizeof(taskTOS));
Uint32ConvertHex(taskTCB->pxTopOfStack, taskTOS);
/* ouput TCB contexts */
char Monitor[150]; memset(Monitor,'\0',sizeof(Monitor));
strcat(Monitor,taskTCB->pcTaskName);
int taskNamelen = strlen(taskTCB->pcTaskName);
for(int t = 0; t < (30-taskNamelen); ++t)
strcat(Monitor," ");
strcat(Monitor,taskBasePriority); strcat(Monitor, "/");
strcat(Monitor,taskPriority); strcat(Monitor," ");
strcat(Monitor,taskStack); strcat(Monitor," ");
strcat(Monitor,taskTOS); strcat(Monitor," ");
strcat(Monitor, taskState); strcat(Monitor, "\n\r");
HAL_UART_Transmit(&huart2,(uint8_t *)Monitor,strlen(Monitor),0xffff);
}
```
### `Taskmonitor()`
```c
void Taskmonitor(void)
{
/* output Title */
char *str="Name |Piority (Base/Actual) |pxStack |pxTopOfStack |State \n\r";
HAL_UART_Transmit(&huart2,(uint8_t *)str,strlen(str),0xffff);
/* traversal ReadyTaskLists */
for (UBaseType_t i = 0; i < configMAX_PRIORITIES; ++i)
{
if (listLIST_IS_EMPTY( &pxReadyTasksLists[i] ) == pdFALSE)
{
ListItem_t *tasklist = listGET_ITEM_OF_HEAD_ENTRY( &pxReadyTasksLists[i] );
UBaseType_t tasklistlen = listCURRENT_LIST_LENGTH( &pxReadyTasksLists[i] );
for (UBaseType_t j = 0; j < tasklistlen; tasklist = tasklist->pxNext, ++j)
{
TCB_t *taskTCB = tasklist->pvOwner;
char taskState[6] = "Ready";
PrintTCBContext (taskTCB, taskState);
}
}
}
/* traversal DelayedTaskList */
if (listLIST_IS_EMPTY( &pxDelayedTaskList[0] ) == pdFALSE)
{
ListItem_t *tasklist = listGET_ITEM_OF_HEAD_ENTRY( &pxDelayedTaskList[0] );
UBaseType_t tasklistlen = listCURRENT_LIST_LENGTH( &pxDelayedTaskList[0] );
for (UBaseType_t j = 0; j < tasklistlen; tasklist = tasklist->pxNext, ++j)
{
TCB_t *taskTCB = tasklist->pvOwner;
char taskState[6] = "Delay";
PrintTCBContext (taskTCB, taskState);
}
}
}
```