STM32F103 transplant FreeRTOS series eleven: list and list items (detailed principle)

Table of contents

11.1 What are list items and list items

11.1.1 List

 11.1.2 List

11.1.3 Mini List Items

11.2 List related API function introduction

11.2.1 Initialization list function vListInitialise()

11.2.2 Initialize list item vListInitialiseItem()

11.2.3 List Insert List Item vListInsert()

11.2.4 Insert list items at the end of the list vListInsertEnd()

11.2.5 List remove list item uxListRemove()


11.1 What are list items and list items

11.1.1 List

Chapter 7 FreeRTOS Lists and List Items

 11.1.2 List items

Everything related to lists is in the files list.c and list.h. A structure called List_t is defined in list.h, as follows:

typedef struct xLIST
{
    	listFIRST_LIST_INTEGRITY_CHECK_VALUE			/* 校验值 */
    	volatile UBaseType_t uxNumberOfItems;			/* 列表中的列表项数量 */
   	    ListItem_t * configLIST_VOLATILE pxIndex		/* 用于遍历列表项的指针 */
    	MiniListItem_t xListEnd					        /* 末尾列表项 */
    	listSECOND_LIST_INTEGRITY_CHECK_VALUE		    /* 校验值 */
} List_t;

(1) and (5), these two are used to check the integrity of the list, you need to set the macro configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES to 1, after opening, a variable xListIntegrityValue1 and xListIntegrityValue2  will be added to these two places, when initializing the list will write a special value to these two variables. FreeRTOS checks the values ​​of these two constants to determine whether the data in the list is damaged during program running. This function is generally used for debugging and is disabled by default. We will not discuss this function when we study lists in the future!

(2), uxNumberOfItems is used to record the number of items in the list ( excluding xListEnd) .

(3), pxIndex is used to record the index number of the current list item for traversing the list.

(4)  The last list item in the xListEnd  list is used to indicate the end of the list. The type of this variable is MiniListItem_t, which is a mini list item. The list item will be explained later.

The schematic diagram of the list structure is shown in the figure:

 Notice! The member variables used for list integrity checking are not shown in the figure.

11.1.3 Mini List Items

Mini list items are defined in the file list.h

struct xMINI_LIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 			/* 用于检测数据完整性 */
	configLIST_VOLATILE TickType_t xItemValue;				/* 列表项的值 */
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;		/* 上一个列表项 */
   	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; 		/* 下一个列表项 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

1. The member variable xItemValue is the value of the list item, which is mostly used to sort the list items in the list in ascending order

2. The member variables pxNext and pxPrevious are respectively used to point to the next list item and the previous list item of the list item in the list

3. The mini list item is only used to mark the end of the list and mount other list items that will be inserted into the list, so the member variables pxOwner and pxContainer are not needed to save memory overhead

4. If only a few member variables are needed, using mini-list items will not cause memory waste.

11.2 List related API function introduction

11.2.1 Initialization list function vListInitialise()

This function is defined in list.c, the function is as follows:

void vListInitialise( List_t * const pxList )
{
    /*  初始化时,列表中只有 xListEnd,因此 pxIndex 指向 xListEnd */
    pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); //(1)

    /* xListEnd 的值初始化为最大值,用于列表项升序排序时,排在最后 */
    pxList->xListEnd.xItemValue = portMAX_DELAY; //(2)

    /* 初始化时,列表中只有 xListEnd,因此上一个和下一个列表项都为 xListEnd 本身 */
    pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); //(3)
    pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); //(4)

    /* 初始化时,列表中的列表项数量为 0(不包含 xListEnd) */
    pxList->uxNumberOfItems = ( UBaseType_t ) 0U; //(5)

    /* 初始化用于检测列表数据完整性的校验值 */
    listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); //(6)
    listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); //(7)
}

(1), xListEnd is used to indicate the end of the list, and pxIndex indicates the index number of the list item. At this time, the list has only one list item, that is xListEnd, so pxIndex points to xListEnd.

(2). The list item value of xListEnd is initialized to portMAX_DELAY. portMAX_DELAY is a macro defined in the file portmacro.h. Depending on the MCU used, the value of portMAX_DELAY is also different, it can be 0xffff or 0xffffffffUL, in this tutorial it is 0xffffffffUL .

(3) Initialize the pxNext variable of the list item xListEnd, because the list has only one list item xListEnd at this time, so pxNext can only point to itself. 
(4) Same as (3), initialize the pxPrevious variable of xListEnd to point to xListEnd itself.

(5) Since there are no other list items at this time, uxNumberOfItems is 0. Note that xListEnd is not counted here.

(6) and (7), the integrity check field in the initialization list item is only valid when the macro configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is 1. Similarly, the written value is different according to the selected MCU, which can be 0x5a5a or 0x5a5a5a5aUL. STM32 is a 32-bit system that writes 0x5a5a5a5aUL.

After the list is initialized, it is shown in Figure 7.2.1.1:

                                  

11.2.2  Initialize list item vListInitialiseItem ()

Like lists, list items also need to be initialized when they are used

void vListInitialiseItem( ListItem_t * const pxItem )
{
    pxItem->pvContainer = NULL; //初始化 pvContainer 为 NULL

    //初始化用于完整性检查的变量,如果开启了这个功能的话。
    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
    listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}

The initialization of the list item is very simple, just initialize the member variable pvContainer of the list item to NULL. List items are initialized according to actual usage

11.2.3 List Insert List Item vListInsert ()

 The insertion operation of the list item is completed by the function vListInsert()

void vListInsert( List_t * const pxList, 
ListItem_t * const pxNewListItem )

keepsake

describe

pxList

the list

pxNewListItem

list item to be inserted

This function is used to sort the list items to be inserted into the list in ascending order of list item values, and insert them into the list in an orderly manner . The specific insertion position of the list item is determined by the member variable xItemValue in the list item. And the inserted list items are arranged in ascending order according to the value of xItemValue !

Here, I will simply post the source code of the development manual. I am too lazy to read the manual for review in the future. If you don’t want to read it, just skip it.

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) 
{
 	ListItem_t * pxIterator; 
	const TickType_t  xValueOfInsertion  =  pxNewListItem->xItemValue; 	/1* 获取列表项的数值依据数值升序排列 */
	listTEST_LIST_INTEGRITY( pxList ); 						/* 2检查参数是否正确 */
	listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); 				

     /*3 如果待插入列表项的值为最大值 */ 
	if( xValueOfInsertion == portMAX_DELAY )
 	{ 
		pxIterator = pxList->xListEnd.pxPrevious; 				/*4 插入的位置为列表 xListEnd 前面 */ 
	} else 
	{
		for(  pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); 			/*5遍历列表中的列表项,找到插入的位置*/ 
		         pxIterator->pxNext->xItemValue <= xValueOfInsertion; 
		         pxIterator = pxIterator->pxNext  ) { }
	} 
	pxNewListItem->pxNext = pxIterator->pxNext;					/*6 将待插入的列表项插入指定位置 */ 
 	pxNewListItem->pxNext->pxPrevious = pxNewListItem; 
	pxNewListItem->pxPrevious = pxIterator; 
	pxIterator->pxNext = pxNewListItem; 
	pxNewListItem->pxContainer = pxList; 						/* 7更新待插入列表项所在列表 */ 
	( pxList->uxNumberOfItems )++;							/* 8更新列表中列表项的数量 */ 

(1) Obtain the value of the list item to be inserted , that is, the value of the member variable xItemValue of the list item, because the position to be inserted in the list item must be determined according to this value.

(2), This line and the next line of code are used to check the integrity of the list and list items . In fact, it is to check whether the variable value used for integrity checking in the list and list items has been changed. The values ​​of these variables are written when the list and list items are initialized. These two lines of code need to implement the function configASSERT()!

(3) To insert a list item, the first step is to get where the list item is to be inserted! If the value of the list item to be inserted is equal to portMAX_DELAY, that is to say, the value of the list item is the maximum value, and the if statement is true, the position to be inserted is at the end of the list.

(4) Obtain the insertion point, pay attention! The xListEnd in the list is used to indicate the end of the list. When the list is initialized, the list value of xListEnd is also portMAX_DELAY. At this time, the list value of the list item to be inserted is also portMAX_DELAY. How should the order of these two be placed? It can be seen from this line of code that the list item to be inserted will be placed in front of xListEnd . pxList->xListEnd.pxPrevious is the mount point at the end of the list

(5) If the value of the list item to be inserted is not equal to portMAX_DELAY, then you need to find your position one by one in the list. This for loop is the process of finding the position. When you find a suitable position for the list item, it will jump out . Since this for loop is used to find the insertion point of the list item, there is nothing inside the body of the for loop. This search process finds the list item insertion point in ascending order. When exiting the loop, pxIterator is the node before pxNewListItem.

(6) After the above search, we have found the insertion point of the list item. The next four lines of code from this line are to insert the list item into the list . The insertion process is similar to the insertion of the doubly linked list in the data structure. This is actually the process of realizing the two-two handle

7). The list item has been inserted into the list, so the member variable pvContainer of the list item should also record which list this list item belongs to. 

8) Add one to the member variable uxNumberOfItems of the list, indicating that another list item has been added .

11.2.4 Insert a list item at the end of the list vListInsertEnd ()

The operation of inserting list items at the end of the list is done through the function vListInsertEnd (), the function prototype is as follows:

This function is used to insert the list item to be inserted into the front of the list item pointed to by the list pxIndex pointer , which is an unordered insertion method

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

       keepsake

describe

       pxList

the list

pxNewListItem

list item to be inserted

code show as below

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
    /* 获取列表 pxIndex 指向的列表项 */
    ListItem_t * const pxIndex = pxList->pxIndex; (0)

    
    listTEST_LIST_INTEGRITY( pxList ); (1)
    listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );

    /* 更新待插入列表项的指针成员变量 */
    pxNewListItem->pxNext = pxIndex; (2)
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;

 	/* 更新列表中原本列表项的指针成员变量 */
    mtCOVERAGE_TEST_DELAY();
    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;

    /* 更新待插入列表项的所在列表成员变量 */
    pxNewListItem->pvContainer = ( void * ) pxList; (3)

    /* 更新列表中列表项的数量 */
    ( pxList->uxNumberOfItems )++; (4)
}

(0) pxIndex indicates the index number of the list item. As mentioned earlier, the pxIndex member variable in the list is used to traverse the list. The list item pointed to by pxIndex is the start list item to be traversed, that is to say, the list item pointed to by pxIndex It represents the head of the list ! Since it is a circular list, the new list item should be inserted in front of the list item pointed to by pxIndex .

(1), complete the integrity check of the list and list items with the following line of code.

(2), the code from the beginning of this line to (3) is to insert the list item to be inserted to the end of the list. When using the function vListInsert() to insert a list item into the list, the position of the list item is determined by the value of the list item, that is, the member variable xItemValue of the list item. vListInsertEnd() adds list items to the end of the list. We know that the xListEnd member variable in the list indicates the end of the list. Does the function vListInsertEnd() insert a list item before or after xListEnd? This is not certain, the so-called end here should be determined according to the member variable pxIndex of the list ! As mentioned earlier, the pxIndex member variable in the list is used to traverse the list, and the list item pointed to by pxIndex is the starting list item to be traversed, that is to say, the list item pointed to by pxIndex represents the head of the list! Since it is a circular list, the new list item should be inserted in front of the list item pointed to by pxIndex.

(3). Mark the new list item pxNewListItem as belonging to the list pxList.

(4) The variable of the number of list items in the recording list is incremented by one, and the number of list items is updated.

This function is used to insert the list item to be inserted into the front of the list item pointed to by the list pxIndex pointer, which is an unordered insertion method

11.2.5 List remove list items uxListRemove ()

UBaseType_t  uxListRemove (   ListItem_t *  const    pxItemToRemove )

This function is used to remove a list item from the list that the list item is in

keepsake

describe

pxItemToRemove

list item to be removed

return value

describe

integer

After the list item to be removed is removed, the number of remaining list items in the list

Detailed code

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
    List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; (1)

    //从列表中移除列表项
    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; (2)
    pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
    
    /*如果 pxIndex 正指向待移除的列表项 */ 
    mtCOVERAGE_TEST_DELAY();
    if( pxList->pxIndex == pxItemToRemove )
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious; (3)
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
     /*将待移除的列表项的所在列表指针清空*/ 
    pxItemToRemove->pvContainer = NULL; (4)

    /*更新列表中列表项的数量*/ 
    ( pxList->uxNumberOfItems )--;

    /*返回移除后的列表中列表项的数量*/ 
    rturn pxList->uxNumberOfItems; (5)
}

(1) To delete a list item, we must first know which list the list item is in, and directly read the member variable pvContainer in the list item to get which list the list item is in .

(2) Complete the deletion of the list item with the following line, which is actually "connecting" the two list items before and after the list item to be deleted.

(3) If the pxIndex of the list just points to the list item to be deleted, then after deleting the list item, it is necessary to find another "object" for pxIndex. This new object is the previous list item of the deleted list item.

(4) The member variable pvContainer of the deleted list item is cleared. Clear the list pointer of the list item to be removed

(5) Return the number of current list items in the new list.

Guess you like

Origin blog.csdn.net/qq_51519091/article/details/131583119