亲测可用。反正没人会看,随便写写就好了...瘪嘴 :)
前景:在使用一些简单的LCD显示屏时,编写菜单,每次都是一个头疼的问题,甚至有些时候牵一发动全身,在想着也没有一种简单的框架,来方便菜单的执行(链表或许是一种不错的选择)
形式:对于一个菜单而言,有上一页,下一页,在某页中还可能会进入下一级,也需要退回到上一级等等,这就需要用到链表的格式,如下
typedef struct List_Node
{
struct List_Node *ppar;
struct List_Node *pchi;
struct List_Node *pnxt;
struct List_Node *plst;
void *pdata;
uint16_t val;
}__attribute__((aligned(1), packed))listInfo_t;
ppar为上一级(父节点),pchi为下一级(子节点),pnxt为下一页,plst为上一页,pdata为这个链表需要存储数据的指针(void *嘛,万用指针),重点是这个val,这个值就是此小型链表框架的精髓
val值:位数(个十百千万)为级数,位数里面的数字为页数,用框架来说的话如下图
基本理念是这样,理论上是能够用满65536个数(算上0),除去最高级(6xxxxx),理论上可以最大广度可以有9页,深度是5级
使用回调函数的形式完成,把每一级看成一个双向循环的链表,然后进行嵌套,遇到下一个不是同级的就进行嵌入或者退出
接下来就是实现它
首先,定义一个结构体,往后的数据只要修改这个结构体即可,例如只修改下面的ct_ListTab
typedef struct
{
uint16_t val;
void *pdata;
}__attribute__((aligned(1), packed))listTabel_t;
static listInfo_t *pListHead = NULL;
listInfo_t *pListCurr = NULL;
static uint8_t st_userdata[0x10] =
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
};
static const listTabel_t ct_ListTab[] =
{
{0, NULL},
{1, NULL},
{11, NULL},
{111, NULL},
{21, (void *)st_userdata},
{31, NULL},
{131, NULL},
{231, NULL},
{41, NULL},
{2, NULL},
{3, NULL},
{13, NULL},
{4, NULL},
};
首先,实现双向链表的节点创建和节点新增
/**
* @brief Create a node
* @param void
* @retval true : listInfo_t*
* @retval fail : NULL
*/
static listInfo_t *user_CreatNode(void)
{
listInfo_t *p = (listInfo_t*)tool_Malloc(sizeof(listInfo_t));
if(p == NULL)
{
return NULL;
}
p->ppar = NULL;
p->pchi = NULL;
p->plst = NULL;
p->pnxt = NULL;
p->pdata = NULL;
return p;
}
/**
* @brief Add a node after the current location to create a new node
* @param listInfo_t* The current node pointer
* @retval true : listInfo_t*
* @retval fail : NULL
*/
static listInfo_t *user_AddNode(listInfo_t *pcur)
{
listInfo_t *pnew = user_CreatNode();
if(pnew == NULL)
{
return NULL;
}
if(pcur == NULL) // If the first pointer is empty, it is created as a pointer header
{
pcur = pnew;
pcur->pnxt = pnew;
pcur->plst = pnew;
}
else if(pcur->pnxt == pcur) // If it is a second linked list
{
pcur->pnxt = pnew;
pcur->plst = pnew;
pnew->pnxt = pcur;
pnew->plst = pcur;
}
else // Three or more
{
pnew->pnxt = pcur->pnxt;
pnew->plst = pcur;
pcur->pnxt->plst = pnew;
pcur->pnxt = pnew;
}
return pnew;
}
使用工具如下
/**
* @brief Calculate how many digits there are in decimal
* @param uint16_t decimal number
* @retval uint16_t uint
*/
static uint8_t tool_DecUint(uint16_t num)
{
uint16_t data = num;
uint8_t res = 0x00;
do
{
res++;
data /= 0x0A;
}while(data);
return res;
}
/**
* @brief Space request function
* @param uint32_t malloc size
* @retval void* data type
*/
void *tool_Malloc(uint32_t size)
{
return malloc(size);
}
/**
* @brief Gets the number of decimal digits
* @param uint8_t loca
* @retval uint8_t muti
*/
static uint8_t user_GetTabMuti(uint8_t loca)
{
return tool_DecUint(ct_ListTab[loca].val);
}
/**
* @brief Gets the largest element of the array
* @param void
* @retval uint16_t element
*/
static uint16_t user_GetTabMax(void)
{
return sizeof(ct_ListTab) / sizeof(listTabel_t);
}
最后就是实现该功能
/**
* @brief Register a linked list
* @param uint8_t table location
* @param listInfo_t* parente pionter
* @retval true: 0x00
* @retval fail: negative number
*/
static int user_List_Reg(uint8_t loca, listInfo_t *ppar)
{
listInfo_t *p = NULL;
uint8_t i = loca;
uint8_t enter = 0x00;
for(i = loca; i < user_GetTabMax(); i++)
{
p = user_AddNode(p);
if(p == NULL)
{
return -i;
} // An error occurs when all applications were cleared before cancellation
else
{
if(i == 0x00)
{
pListHead = p; // Defines the pointer header
}
else
{
pListCurr = p; // Keep the current node
}
/* USER CODE BEGIN List_Init 1 */
p->val = ct_ListTab[i].val; // Attach the page number
p->pdata = ct_ListTab[i].pdata;
/* USER CODE END List_Init 1 */
if(ppar != NULL)
{
if(i == loca)
{
ppar->pchi = p;
} // Identify child nodes
p->ppar = ppar; // Confirm the parent node
}
if((i + 0x01) < user_GetTabMax()) // The next one cannot exceed the largest array
{
if((user_GetTabMuti(i + 0x01)) > user_GetTabMuti(i)) // Determines whether the next bit is greater than the previous one dimension
{
enter = user_GetTabMuti(i); // The value of the dimension is retained
i = user_List_Reg(i + 0x01, p); // Enter recursion
if(enter < user_GetTabMuti(i)) // Determine whether the recursive returned dimension is the same as the loop
{
if((user_GetTabMuti(i + 0x01) + 0x01) == user_GetTabMuti(i))
{
// Make sure the next number is not a fault, such as 121 - 31
}
else
{
return i + 0x01; // If so, offset backwards and back
}
}
else
{
i--; // If the same is the case, the loop is subtracted by one, because it will be added before the next loop
}
}
else if(user_GetTabMuti(i + 0x01) < user_GetTabMuti(i)) // If the next dimension is judged to be smaller than the previous dimension
{
return i;
}
}
else
{
}
}
}
pListCurr = pListHead;
return i;
}
咱们来验证一下,初始化结束之后,打印数据
log_debug("val = %d, data = %d", pListCurr->pnxt->pchi->pnxt->val, ((uint8_t *)pListCurr->pnxt->pchi->pnxt->pdata)[0x05]);
打印结果为:
-> Debug : val = 21, data = 6
故:在最后使用的时候,在使用的时候,只需要调用函数user_List_Reg(0x00, NULL),而且修改最初的那个结构体数组即可完成整个链表的改变,其他功能,就比如回到链表头啊,根据val数值找到某个链表所在的位置啊就比较简单了
毕竟~,反正没人会看