diff --git a/Core/AdcFilter.c b/Core/AdcFilter.c
new file mode 100644
index 0000000..0c43834
--- /dev/null
+++ b/Core/AdcFilter.c
@@ -0,0 +1,66 @@
+
+#include "AdcFilter.h"
+#include "math.h"
+
+/// <summary>初始化滤波器</summary>
+bool AdcFilterInit(AdcFilter_t* filter, short size)
+{
+ if(filter == NULL)return false;
+ if(size < 4)size = 4;
+
+ filter->Data = (short*)malloc(sizeof(short)*size);
+ if(filter->Data == NULL)return false;
+
+ memset(filter->Data, 0, sizeof(short)*size);
+ filter->Size = size;
+ filter->Index = 0;
+ return true;
+}
+
+/// <summary>滤波数据</summary>
+/// <param name="filter">滤波器</param>
+/// <param name="data">原始数据</param>
+/// <returns>数据放入成功</returns>
+bool AdcFilterPush(AdcFilter_t* filter,short data)
+{
+ if(filter == NULL)return false;
+ if(filter->Data == NULL)return false;
+
+ // 保存数据
+ filter->Data[filter->Index] = data;
+ // 更新索引
+ filter->Index++;
+ if(filter->Index >= filter->Size)filter->Index = 0;
+
+ return true;
+}
+
+/// <summary>滤波数据</summary>
+/// <param name="filter">滤波器</param>
+/// <param name="valueMax">X Y 的最大值,绝对值</param>
+/// <param name="outRange">换算为这个范围,ADC数值转换为对外输出范围,绝对值</param>
+/// <returns>滤波之后的数据</returns>
+short AdcFilterCalc(AdcFilter_t* filter, int valueMax, int outRange)
+{
+ // 滤波
+ int sum = 0;
+ int min = INT32_MAX;
+ int max = INT32_MIN;
+ for(int i = 0; i < filter->Size; i++)
+ {
+ sum += filter->Data[i];
+ if(filter->Data[i] < min)min = filter->Data[i];
+ if(filter->Data[i] > max)max = filter->Data[i];
+ }
+ // 去除最大最小值
+ sum -= min;
+ sum -= max;
+
+ // 滤波后的数值
+ int result = sum / (filter->Size - 2);
+
+ // 范围转换
+ result = (result * outRange) / valueMax;
+ return (short)result;
+}
+
diff --git a/Core/AdcFilter.h b/Core/AdcFilter.h
new file mode 100644
index 0000000..f64c6b2
--- /dev/null
+++ b/Core/AdcFilter.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "Type.h"
+
+/// <summary>滤波器</summary>
+typedef struct
+{
+ short* Data;
+ short Size;
+ short Index;
+}AdcFilter_t;
+
+
+/// <summary>初始化滤波器</summary>
+bool AdcFilterInit(AdcFilter_t* filter, short size);
+
+/// <summary>滤波数据</summary>
+/// <param name="filter">滤波器</param>
+/// <param name="data">原始数据</param>
+/// <returns>数据放入成功</returns>
+bool AdcFilterPush(AdcFilter_t* filter,short data);
+
+/// <summary>滤波数据</summary>
+/// <param name="filter">滤波器</param>
+/// <param name="valueMax">X Y 的最大值,绝对值</param>
+/// <param name="outRange">换算为这个范围,ADC数值转换为对外输出范围,绝对值</param>
+/// <returns>滤波之后的数据</returns>
+short AdcFilterCalc(AdcFilter_t* filter, int valueMax, int outRange);
+
diff --git a/Core/cJSON.c b/Core/cJSON.c
index 4e51dec..6e8c278 100644
--- a/Core/cJSON.c
+++ b/Core/cJSON.c
@@ -45,7 +45,7 @@ static char* cJSON_strdup(const char* str)
// 设置 malloc free
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
- if (!hooks)
+ if (hooks == NULL)
{
cJSON_malloc = GlobleMalloc;
cJSON_free = GlobleFree;
diff --git a/Core/ConfigBase.c b/Core/ConfigBase.c
index fac75b7..91824a3 100644
--- a/Core/ConfigBase.c
+++ b/Core/ConfigBase.c
@@ -100,3 +100,361 @@ bool CleanConfig(uint addr)
return rs;
}
+
+
+
+#include "Crc.h"
+#include "Array.h"
+
+// Config 有效性 取决于 MagicNum SaveIdx Crc32
+typedef struct
+{
+ // 配置实际内容。
+ Config_t Config;
+
+ // 魔数 内部使用。 外部不要碰
+ // 默认为 : 'M' 'a' 'g' '&' 0x4D616726
+ uint MagicNum;
+ // 保存号,也是位置号。内部使用。外部不要碰 0-65535
+ ushort Index;
+ // 校验 内部使用。 外部不要碰
+ ushort Crc16;
+}FConfigItem_t;
+
+/// <summary>修正内部数据</summary>
+/// <param name="cfg">配置</param>
+/// <param name="idx">必要条件</param>
+/// <returns></returns>
+static void FixFCfg(FConfigItem_t* cfg, ushort idx)
+{
+ cfg->Index = idx;
+ cfg->MagicNum = 0x4D616726;
+ byte* p = (byte*)cfg;
+ int len = offsetof2(FConfigItem_t,Crc16);
+ cfg->Crc16 = CaclcCRC16_MODBUS(p, len);
+ // cfg->Crc16 = CaclcCRC16_MODBUS(p,sizeof(FConfigItem_t) - 2);
+}
+
+/// <summary>检查配置是否有效</summary>
+/// <param name="cfg"></param>
+/// <returns></returns>
+static bool FCfgIsOK(FConfigItem_t* cfg)
+{
+ if(cfg == NULL)return false;
+ if(cfg->MagicNum != 0x4D616726)return false;
+
+ byte* p = (byte*)cfg;
+ int len = offsetof2(FConfigItem_t,Crc16);
+ ushort cl = CaclcCRC16_MODBUS(p, len);
+ // ushort cl = CaclcCRC16_MODBUS(p,sizeof(FConfigItem_t) - 2);
+ if(cl != cfg->Crc16)return false;
+
+ return true;
+}
+
+/// <summary>所在块的块地址</summary>
+/// <param name="ctl"></param>
+/// <param name="idx"></param>
+/// <returns></returns>
+static uint FCfgSecAddr(FCfgCtrl_t* ctl,int idx)
+{
+ // 块个数
+ int sCnt = 1 << ctl->FSecBit;
+ // 所在块
+ int sec = idx & (sCnt - 1);
+ // 块地址
+ uint addr = ctl->FSecAddrs[sec];
+ return addr;
+}
+
+// #define FSECADDR(ctl,idx) (ctl->FSecAddrs[(idx & ((1 << ctl->FSecBit) - 1)))])
+// FSECADDR FCfgSecAddr
+
+/// <summary>块内偏移量</summary>
+/// <param name="ctl"></param>
+/// <param name="idx"></param>
+/// <returns></returns>
+static uint FSecOffset(FCfgCtrl_t* ctl,int idx)
+{
+ // 块内编号
+ idx >>= ctl->FSecBit;
+ // 块内个数
+ int cCnt = 1 << ctl->FSecCfgBit;
+ // 取余
+ int sidx = idx & (cCnt - 1);
+ // 块内偏移
+ uint offset = sizeof(FConfigItem_t) * sidx;
+ return offset;
+}
+
+// #define FSECOFFSET(ctl,idx) (sizeof(FConfigItem_t) * ((idx >> ctl->FSecBit) & (1 << ctl->FSecCfgBit) - 1))))
+// #define FSECOFFSET FSecOffset
+
+/// <summary>初始化</summary>
+/// <param name="ctl"></param>
+/// <param name="api">NOR FLASH 接口</param>
+/// <param name="sad">FLASH 块地址数组</param>
+/// <param name="sadlen">块数组长度</param>
+/// <param name="ccnt">块内 存放配置的份数</param>
+/// <returns>0 无错</returns>
+int FCfgInit(FCfgCtrl_t* ctl, NorFlash_t* api, uint* sad, byte sadlen, byte ccnt)
+{
+ int err = 0;
+ byte temp = 0;
+ if(ctl == NULL){ err = __LINE__; goto reserr; }
+ if(api == NULL){ err = __LINE__; goto reserr; }
+ if(sad == NULL){ err = __LINE__; goto reserr; }
+ if(sadlen < 2) { err = __LINE__; goto reserr; }
+ if(ccnt < 1) { err = __LINE__; goto reserr; }
+
+ memcpy(&ctl->FApi,api,sizeof(NorFlash_t));
+ ctl->FSecAddrs = sad;
+
+ // 计算位数
+ temp = 0;
+ for (int i = 1; ; i++)
+ {
+ int cnt = 1 << i;
+ if(sadlen >= cnt)temp = i;
+ else break;
+ }
+ ctl->FSecBit = temp;
+
+ temp = 0;
+ for (int i = 0; ; i++)
+ {
+ int cnt = 1 << i;
+ if(ccnt >= cnt)temp = i;
+ else break;
+ }
+ ctl->FSecCfgBit = temp;
+ return 0;
+
+ reserr:
+ DebugPrintf("%s [%d] ERROR\r\n",__func__,__LINE__);
+ return err;
+}
+
+/// <summary>扫描整个 FLASH 存储区,找到最新且有效的配置取出来</summary>
+/// <param name="ctl"></param>
+/// <param name="cfg"></param>
+/// <returns></returns>
+bool FCfgLoad(FCfgCtrl_t* ctl, Config_t* cfg)
+{
+ if(ctl == NULL)return false;
+ if(ctl->FSecAddrs == NULL)return false;
+ if(ctl->FSecBit < 1)return false;
+ if(cfg == NULL)return false;
+
+ // 最大同时存在配置个数
+ int limit = (1 << ctl->FSecBit) * (1 << ctl->FSecCfgBit);
+ // 已存在最大IDX
+ int max = -1;
+ // 小于limit的,已存在最大IDX
+ int limitMax = -1;
+
+ FConfigItem_t temp;
+ FConfigItem_t* fp = &temp;
+ // 块个数
+ int slen = 1 << ctl->FSecBit;
+ // 块内配置个数
+ int sCfgCnt = 1 << ctl->FSecCfgBit;
+
+ for (int i = 0; i < slen; i++)
+ {
+ // 块首地址
+ uint base = ctl->FSecAddrs[i];
+ for (int j = 0; j < sCfgCnt; j++)
+ {
+ // 得到地址
+ uint addr = sizeof(FConfigItem_t) * j + base;
+
+ if(ctl->FApi.FlashRead != NULL)
+ {
+ // 读取 配置项
+ memset(fp, 0x00, sizeof(FConfigItem_t));
+ if(!ctl->FApi.FlashRead(addr,(byte*)fp,sizeof(FConfigItem_t)))continue;
+ }
+ else
+ {
+ // 直接指针过去
+ fp = (FConfigItem_t*)addr;
+ }
+
+ // 配置有效性检查
+ if(!FCfgIsOK(fp))continue;
+
+ // 选取最后存入的 idx
+ ushort idx = fp->Index;
+ if(idx > max)max = idx;
+ if(idx < limit)
+ {
+ if(idx > limitMax)limitMax = idx;
+ }
+ }
+ }
+
+ // 没有任何有效配置
+ if(max == -1)
+ {
+ ctl->CurrIndex = 0;
+ memset(&ctl->CurrCfg,0x00,sizeof(FConfigItem_t));
+ return false;
+ }
+
+ // 判定最后写入是哪个
+ int last = -1;
+ if((max > 65535 - limit) && (limitMax != -1))
+ {
+ // 刚好跨界了。大的被丢弃。使用小的里面最大的。
+ last = limitMax;
+ }
+ else
+ {
+ last = max;
+ }
+
+ // 块地址 + 块内偏移
+ uint addr = FCfgSecAddr(ctl,last) + FSecOffset(ctl,last);
+ if(ctl->FApi.FlashRead != NULL)
+ {
+ // 读取 配置项
+ memset(fp, 0x00, sizeof(FConfigItem_t));
+ ctl->FApi.FlashRead(addr,(byte*)fp,sizeof(FConfigItem_t));
+ }
+ else
+ {
+ // 直接指针过去
+ fp = (FConfigItem_t*)addr;
+ }
+
+ memcpy(&ctl->CurrCfg,&fp->Config,sizeof(Config_t));
+ ctl->CurrIndex = fp->Index;
+
+ memcpy(cfg,&ctl->CurrCfg,sizeof(Config_t));
+ return true;
+}
+
+/// <summary>写配置进去,地址为块首地址的时候擦除块。</summary>
+/// <param name="ctl"></param>
+/// <param name="cfg"></param>
+/// <returns></returns>
+static bool FCfgWrite(FCfgCtrl_t* ctl, FConfigItem_t* cfg)
+{
+ if(ctl->FApi.FlashWrite == NULL)return false;
+
+ int idx = cfg->Index;
+ // 块地址
+ uint addr = FCfgSecAddr(ctl,idx);
+ // 块内偏移
+ uint offset = FSecOffset(ctl,idx);
+
+ if(offset == 0)
+ {
+ if(ctl->FApi.FlashErase == NULL)return false;
+ if(!ctl->FApi.FlashErase(addr))return false;
+ }
+
+ // 写
+ return ctl->FApi.FlashWrite(addr + offset, (byte*)cfg, sizeof(FConfigItem_t));
+}
+
+/// <summary>保存配置</summary>
+/// <param name="ctl"></param>
+/// <param name="cfg"></param>
+/// <returns></returns>
+bool FCfgSave(FCfgCtrl_t* ctl, Config_t* cfg)
+{
+ if(ctl == NULL)return false;
+ if(ctl->FSecAddrs == NULL)return false;
+ if(ctl->FSecBit < 1)return false;
+ if(cfg == NULL)return false;
+
+ // 相同,不存。
+ Config_t* curr = &ctl->CurrCfg;
+ if(!ArrayEqual((byte*)cfg, (byte*)curr,sizeof(Config_t)))return true;
+
+ // 下一个位置保存
+ ushort idx = ctl->CurrIndex + 1;
+ FConfigItem_t item;
+ memcpy(&item.Config,cfg,sizeof(Config_t));
+ FixFCfg(&item,idx);
+ bool res = FCfgWrite(ctl, &item);
+ // 保存完成,更新本地信息
+ if(res)
+ {
+ memcpy(&ctl->CurrCfg,cfg,sizeof(Config_t));
+ ctl->CurrIndex = item.Index;
+ }
+
+ return res;
+}
+
+/// <summary>删除一个配置</summary>
+/// <param name="ctl"></param>
+/// <param name="idx"></param>
+/// <returns></returns>
+bool FCfgClean(FCfgCtrl_t* ctl, int idx)
+{
+ if(ctl->FApi.FlashWrite == NULL)return false;
+
+ // 块地址
+ uint addr = FCfgSecAddr(ctl,idx);
+ // 块内偏移
+ uint offset = FSecOffset(ctl,idx);
+
+ // 配置内 magic 位置
+ offset += offsetof2(FConfigItem_t,MagicNum);
+
+ // FLASH 擦完是 ff 只能往 00 写
+ uint magic = 0;
+ return ctl->FApi.FlashWrite(addr+offset, (byte*)&magic, sizeof(magic));
+}
+
+/// <summary>擦除所有 FLASH 区域,一个不留</summary>
+/// <param name="ctl"></param>
+/// <returns></returns>
+bool FCfgCleanAll(FCfgCtrl_t* ctl)
+{
+ if(ctl == NULL)return false;
+ if(ctl->FSecAddrs == NULL)return false;
+ if(ctl->FSecBit < 1)return false;
+ if(ctl->FApi.FlashErase == NULL)return false;
+
+ int slen = 1 << ctl->FSecBit;
+ for (int i = 0; i < slen; i++)
+ {
+ ctl->FApi.FlashErase(ctl->FSecAddrs[i]);
+ }
+ ctl->CurrIndex = 0;
+
+ return true;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/ConfigBase.h b/Core/ConfigBase.h
index b6fb9a1..8ce565b 100644
--- a/Core/ConfigBase.h
+++ b/Core/ConfigBase.h
@@ -32,3 +32,133 @@ bool SetConfig(Config_t* cfg, uint addr);
// 删除配置内容
bool CleanConfig(uint addr);
+/***************************************************************/
+/*
+写很多份配置的驱动。
+NOR FLASH 作为存储载体。
+多擦除块设计。
+处理写入时断电问题。
+*/
+
+// 块:擦除块
+typedef struct
+{
+ // FLASH 写
+ bool (*FlashWrite)(uint address, byte* buf, int len);
+ // 可以直接通过指针访问的 addr ,此函数为 NULL。
+ bool (*FlashRead)(uint address, byte* buf, int len);
+ // FLASH 擦块
+ bool (*FlashErase)(uint address);
+}NorFlash_t;
+
+// 对象
+typedef struct
+{
+ // 内当前最新配置,用于对比是否需要写入。
+ Config_t CurrCfg;
+ // NOR FLASH 接口
+ NorFlash_t FApi;
+ // FLASH Section 地址数组,数组长度是 FlashSecCnt
+ uint* FSecAddrs;
+ // FLASH Section 块个数。 个数 FlashSecCnt = (1 << FSecBit)
+ byte FSecBit;
+ // FLASH Section 存 Config_t 的份数 = (1 << FSecCfgBit)
+ byte FSecCfgBit;
+
+ // 当前使用的 IDEX 。也是存放位置。
+ ushort CurrIndex;
+}FCfgCtrl_t;
+
+/*
+// FLASH 擦除块地址
+const uint secAddr[] =
+{
+ 0 + 0x8000000 + (48 * 1024),
+ 1024 + 0x8000000 + (48 * 1024),
+ 2048 + 0x8000000 + (48 * 1024),
+ 4096 + 0x8000000 + (48 * 1024)
+};
+
+// 单片机内部 NOR FLASH
+NorFlash_t nfunc =
+{
+ .FlashWrite = XXX
+ .FlashRead = NULL,
+ .FlashErase = XXX,
+};
+
+// 直接定义
+FCfgCtrl_t FCtl =
+{
+ .FlashWrite = xxx,
+ .FlashErase = xxx,
+ .BaseAddrs = secAddr,
+ .FSecCnt = 2, // (1<<2) 有4块
+ .FSecCfgCnt = 3, // (1<<3) 存8份
+ .CfgIndex = 0,
+};
+
+使用 FCfgInit 函数配置
+FCfgInit(&FCtl, &nfunc, secAddr, ArrayLength(secAddr), 8);
+
+*/
+
+/// <summary>初始化</summary>
+/// <param name="ctl"></param>
+/// <param name="api">NOR FLASH 接口</param>
+/// <param name="sad">FLASH 块地址数组</param>
+/// <param name="sadlen">块数组长度</param>
+/// <param name="ccnt">块内 存放配置的份数</param>
+/// <returns>0 无错</returns>
+int FCfgInit(FCfgCtrl_t* ctl, NorFlash_t* api, uint* sad, byte sadlen, byte ccnt);
+
+/// <summary>扫描整个 FLASH 存储区,找到最新且有效的配置取出来</summary>
+/// <param name="ctl"></param>
+/// <param name="cfg"></param>
+/// <returns></returns>
+bool FCfgLoad(FCfgCtrl_t* ctl, Config_t* cfg);
+
+/// <summary>保存配置</summary>
+/// <param name="ctl"></param>
+/// <param name="cfg"></param>
+/// <returns></returns>
+bool FCfgSave(FCfgCtrl_t* ctl, Config_t* cfg);
+
+/// <summary>删除一个配置,应该用不到</summary>
+/// <param name="ctl"></param>
+/// <param name="idx"></param>
+/// <returns></returns>
+bool FCfgClean(FCfgCtrl_t* ctl, int idx);
+
+/// <summary>擦除所有 FLASH 区域,一个不留</summary>
+/// <param name="ctl"></param>
+/// <returns></returns>
+bool FCfgCleanAll(FCfgCtrl_t* ctl);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/MyList.c b/Core/MyList.c
index 9357acd..8abea7d 100644
--- a/Core/MyList.c
+++ b/Core/MyList.c
@@ -1,161 +1,19 @@
-
-#include "MyList.h"
-
-// #define ListPrintf DebugPrintf
-#define ListPrintf(...)
-
-/*
-后期优化措施,减少malloc free 使用C# List策略 批量申请,自动扩容。
-另外 如果重要数据,上层做处理,定期写入Flash然后 再读出,避免内存泄漏!!!
-*/
-
-void ListInit(MyList_t* list)
-{
- list->head = NULL;
- list->count = 0;
-}
-
-bool ListAdd(MyList_t* list, void* data, isEquiFunc isEqui)
-{
- if ((list->head) == NULL)
- {
- MyListItem_t* item = (MyListItem_t*)MyListMalloc(sizeof(MyListItem_t));
- if (!item)return false;
- ListPrintf("ListAdd Item %08X : %08X\r\n", item, data);
- item->Data = data;
- item->_next = NULL;
- list->count = 1;
-
- list->head = item;
- return true;
- }
- else
- {
- if (isEqui != NULL)
- {
- if (ListFindItem(list, data, isEqui) != NULL)
- {
- ListPrintf("ListAdd this data exist.\r\n");
- return true;
- }
- }
- MyListItem_t* item = (MyListItem_t*)MyListMalloc(sizeof(MyListItem_t));
- if (!item)return false;
- ListPrintf("ListAdd Item %08X : %08X\r\n", item, data);
- item->Data = data;
- item->_next = list->head;
-
- list->count++;
- list->head = item;
- return true;
- }
-}
-
-void* ListFind(MyList_t* list, void* data, isEquiFunc isEqui)
+#include "MyList.h"
+
+/**
+ * 获取链表长度
+ * @param head 链表头指针
+ * @return 链表节点数量(不包括头节点)
+ */
+uint ListGetLength(ListHead* head)
{
- MyListItem_t* item = list->head;
- while (1)
- {
- if (item == NULL)break;
-
- if (isEqui(item->Data, data))break;
-
- item = item->_next;
- }
- if (item != NULL) return item->Data;
- return NULL;
-}
-
-MyListItem_t* ListFindItem(MyList_t* list, void* data, isEquiFunc isEqui)
-{
- MyListItem_t* item = list->head;
- while (1)
- {
- if (item == NULL)break;
-
- if (isEqui(item->Data, data))break;
-
- item = item->_next;
- }
- return item;
-}
-
-bool ListRemove(MyList_t* list, void* data, isEquiFunc isEqui)
-{
- MyListItem_t* pre = list->head;
- MyListItem_t* item = list->head;
- while (1)
- {
- if (item == NULL)break;
-
- if (isEqui(item->Data, data))
- {
- if (pre == item)
- list->head = item->_next;
- else
- pre->_next = item->_next;
-
- list->count--;
- ListPrintf("ListRemove Item %08X : %08X\r\n", item, item->Data);
- MyListFree(item);
- return true;
- }
- pre = item;
- item = item->_next;
- }
- return false;
-}
-
-bool ListRemoveWithCallBack(MyList_t* list, void* data, isEquiFunc isEqui, ListCallBack callBack)
-{
- MyListItem_t* pre = list->head;
- MyListItem_t* item = list->head;
- while (1)
- {
- if (item == NULL)break;
-
- if (isEqui(item->Data, data))
- {
- if (pre == item)
- list->head = item->_next;
- else
- pre->_next = item->_next;
-
- list->count--;
- ListPrintf("ListRemove Item %08X : %08X & callback:\r\n", item, item->Data);
- callBack(item->Data);
- MyListFree(item); // while内有判断 此处item不为NULL
- return true;
- }
- pre = item;
- item = item->_next;
- }
-
- return false;
-}
-
-void* ListChange(MyList_t* list, void* src, void* dst, isEquiFunc isEqui)
-{
- // if ((*head) == NULL)return NULL;
-
- MyListItem_t* item = list->head;
- while (1)
- {
- if (item == NULL)break;;
-
- if (isEqui(item->Data, src))
- {
- ListPrintf("ListChange Item %08X %08X -> %08X\r\n", item, src, dst);
- item->Data = dst;
- break;
- }
- item = item->_next;
- }
- if (item == NULL)
- {
- ListPrintf("ListChange Fail,src exist\r\n");
- return NULL;
- }
-
- return item->Data;
+ uint length = 0;
+ ListNode* node;
+
+ ListForEach(node, head)
+ {
+ length++;
+ }
+
+ return length;
}
diff --git a/Core/MyList.h b/Core/MyList.h
index 713ab3c..53746e8 100644
--- a/Core/MyList.h
+++ b/Core/MyList.h
@@ -6,54 +6,257 @@
#include "Type.h"
#include "Debug.h"
-#include "FreeRTOS.h"
+/**
+ * 侵入式双向循环链表
+ * 参考Linux内核链表实现
+ * 使用方法:在结构体中包含 ListHead 成员
+ */
+/* 链表节点定义 */
+typedef struct ListNode
+{
+ struct ListNode* Previous;
+ struct ListNode* Next;
+} ListNode;
+
+/* 链表头定义(与节点结构相同) */
+typedef ListNode ListHead;
+
+/**
+ * 初始化链表头
+ * @param head 链表头指针
+ */
+static inline void InitListHead(ListHead* head)
+{
+ head->Previous = head;
+ head->Next = head;
+}
+
+/**
+ * 判断链表是否为空
+ * @param head 链表头指针
+ * @return true 表示空,false 表示非空
+ */
+static inline bool ListIsEmpty(const ListHead* head)
+{
+ return head->Next == head;
+}
+
+/**
+ * 判断链表是否只有一个节点(只有头节点)
+ * @param head 链表头指针
+ * @return true 表示只有头节点,false 表示有多于一个节点
+ */
+static inline bool ListIsSingle(const ListHead* head)
+{
+ return head->Next == head->Previous;
+}
+
+/**
+ * 在两个节点之间插入新节点
+ * @param prev 前驱节点
+ * @param next 后继节点
+ * @param newNode 要插入的新节点
+ */
+static inline void ListInsertBetween(ListNode* prev, ListNode* next, ListNode* newNode)
+{
+ next->Previous = newNode;
+ newNode->Next = next;
+ newNode->Previous = prev;
+ prev->Next = newNode;
+}
-#define MyListMalloc pvPortMalloc
-#define MyListFree vPortFree
+/**
+ * 在链表头部插入节点(在head之后插入)
+ * @param head 链表头指针
+ * @param newNode 要插入的新节点
+ */
+static inline void ListAdd(ListHead* head, ListNode* newNode)
+{
+ ListInsertBetween(head, head->Next, newNode);
+}
-// 内部使用一些Cache,避免 malloc 太占 cpu 资源
-// #define ListItemCacheSize 5
+/**
+ * 在链表尾部插入节点(在head之前插入,即链表末尾)
+ * @param head 链表头指针
+ * @param newNode 要插入的新节点
+ */
+static inline void ListAddTail(ListHead* head, ListNode* newNode)
+{
+ ListInsertBetween(head->Previous, head, newNode);
+}
-/*
- List结构
- 单向链表,一个数据指针,一个结构体next指针。
- 对比数据是否相等,采用钩子函数完成。isEquiFunc 多半函数提供此钩子
- 删除数据项的时候提供其它动作的ListCallBack钩子,可以做数据项释放等操作。
- 强烈建议 定义了List_t 后 ListInit()初始化一下 避免拿到的内存有脏数据。
-*/
+/**
+ * 从链表中删除节点
+ * @param node 要删除的节点
+ */
+static inline void ListDel(ListNode* node)
+{
+ node->Previous->Next = node->Next;
+ node->Next->Previous = node->Previous;
+ node->Previous = NULL;
+ node->Next = NULL;
+}
+
+/**
+ * 从链表中删除节点并重新初始化
+ * @param node 要删除的节点
+ */
+static inline void ListDelInit(ListNode* node)
+{
+ ListDel(node);
+ InitListHead(node);
+}
-struct MyListItem
+/**
+ * 将节点从一个链表移动到另一个链表的头部
+ * @param head 目标链表头指针
+ * @param node 要移动的节点
+ */
+static inline void ListMove(ListHead* head, ListNode* node)
{
- void* Data; // 链表数据项
- struct MyListItem* _next; // 链表连接项
-};
-typedef struct MyListItem MyListItem_t;
+ ListDel(node);
+ ListAdd(head, node);
+}
-typedef struct
+/**
+ * 将节点从一个链表移动到另一个链表的尾部
+ * @param head 目标链表头指针
+ * @param node 要移动的节点
+ */
+static inline void ListMoveTail(ListHead* head, ListNode* node)
{
- MyListItem_t* head; // 头指针
- int count; // 数据项计数
-}MyList_t;
+ ListDel(node);
+ ListAddTail(head, node);
+}
+
+/**
+ * 遍历链表(不安全,不能在遍历时删除节点)
+ * @param pos 当前遍历到的节点指针
+ * @param head 链表头指针
+ */
+#define ListForEach(pos, head) \
+ for (pos = (head)->Next; pos != (head); pos = pos->Next)
+
+/**
+ * 遍历链表(安全版本,可以在遍历时删除节点)
+ * @param pos 当前遍历到的节点指针
+ * @param n 用于临时存储下一个节点的指针
+ * @param head 链表头指针
+ */
+#define ListForEachSafe(pos, n, head) \
+ for (pos = (head)->Next, n = pos->Next; pos != (head); \
+ pos = n, n = pos->Next)
+
+/**
+ * 遍历链表,从尾部开始(不安全)
+ * @param pos 当前遍历到的节点指针
+ * @param head 链表头指针
+ */
+#define ListForEachPrev(pos, head) \
+ for (pos = (head)->Previous; pos != (head); pos = pos->Previous)
+
+/**
+ * 遍历链表,从尾部开始(安全版本)
+ * @param pos 当前遍历到的节点指针
+ * @param n 用于临时存储上一个节点的指针
+ * @param head 链表头指针
+ */
+#define ListForEachPrevSafe(pos, n, head) \
+ for (pos = (head)->Previous, n = pos->Previous; pos != (head); \
+ pos = n, n = pos->Previous)
+
+/**
+ * 通过链表节点获取父结构体指针
+ * @param node 链表节点指针
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListEntry(node, type, member) \
+ container_of(node, type, member)
-typedef bool(*isEquiFunc)(void* data1, void* data2);
-typedef bool(*ListCallBack)(void* data);
+/**
+ * 遍历链表并获取父结构体(不安全版本)
+ * @param pos 存储父结构体指针的变量
+ * @param head 链表头指针
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListForEachEntry(pos, head, type, member) \
+ for (pos = ListEntry((head)->Next, type, member); \
+ &pos->member != (head); \
+ pos = ListEntry(pos->member.Next, type, member))
-void ListInit(MyList_t* list);
+/**
+ * 遍历链表并获取父结构体(安全版本)
+ * @param pos 存储父结构体指针的变量
+ * @param n 临时存储下一个父结构体指针的变量
+ * @param head 链表头指针
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListForEachEntrySafe(pos, n, head, type, member) \
+ for (pos = ListEntry((head)->Next, type, member), \
+ n = ListEntry(pos->member.Next, type, member); \
+ &pos->member != (head); \
+ pos = n, n = ListEntry(n->member.Next, type, member))
-bool ListAdd(MyList_t* list, void* data, isEquiFunc isEqui);
+/**
+ * 遍历链表并获取父结构体,从尾部开始(不安全版本)
+ * @param pos 存储父结构体指针的变量
+ * @param head 链表头指针
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListForEachEntryPrev(pos, head, type, member) \
+ for (pos = ListEntry((head)->Previous, type, member); \
+ &pos->member != (head); \
+ pos = ListEntry(pos->member.Previous, type, member))
-void* ListFind(MyList_t* list, void* data, isEquiFunc isEqui);
+/* 链表相关函数声明 */
-bool ListRemove(MyList_t* list, void* data, isEquiFunc isEqui);
+/**
+ * 获取链表长度
+ * @param head 链表头指针
+ * @return 链表节点数量(不包括头节点)
+ */
+uint ListGetLength(ListHead* head);
-bool ListRemoveWithCallBack(MyList_t* list, void* data, isEquiFunc isEqui, ListCallBack callBack);
+/**
+ * 获取链表第一个节点的数据(如果为空返回NULL)
+ * @param head 链表头指针
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListFirstEntry(head, type, member) \
+ (ListIsEmpty(head) ? NULL : ListEntry((head)->Next, type, member))
-void* ListChange(MyList_t* list, void* src, void* dst, isEquiFunc isEqui);
+/**
+ * 获取链表最后一个节点的数据(如果为空返回NULL)
+ * @param head 链表头指针
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListLastEntry(head, type, member) \
+ (ListIsEmpty(head) ? NULL : ListEntry((head)->Previous, type, member))
-// 纠结是否放出来使用
-MyListItem_t* ListFindItem(MyList_t* list, void* data, isEquiFunc isEqui);
+/**
+ * 获取下一个节点的数据
+ * @param node 当前节点
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListNextEntry(node, type, member) \
+ (ListEntry((node)->member.Next, type, member))
+/**
+ * 获取上一个节点的数据
+ * @param node 当前节点
+ * @param type 父结构体类型
+ * @param member 链表节点在父结构体中的成员名
+ */
+#define ListPrevEntry(node, type, member) \
+ (ListEntry((node)->member.Previous, type, member))
-#endif // !__List_H__
+#endif
diff --git a/Core/StateMachine.c b/Core/StateMachine.c
index 45bb26a..5dc14bb 100644
--- a/Core/StateMachine.c
+++ b/Core/StateMachine.c
@@ -1,17 +1,17 @@
#include "StateMachine.h"
-/// @brief 初始化状态机
-/// @param sm
-/// @param items
+/// <summary>初始化状态机</summary>
+/// <param name="sm"></param>
+/// <param name="items"></param>
void StateMachineInit(StateMachine_t* sm, SMItem_t* items)
{
sm->Current = NULL;
sm->Next = items;
}
-/// @brief 状态机主循环
-/// @param sm
+/// <summary>状态机主循环</summary>
+/// <param name="sm"></param>
void StateMachineMain(StateMachine_t* sm)
{
if(sm == NULL)return;
@@ -43,9 +43,9 @@ void StateMachineMain(StateMachine_t* sm)
}
}
-/// @brief 切换状态
-/// @param sm
-/// @param next
+/// <summary>切换状态</summary>
+/// <param name="sm"></param>
+/// <param name="next"></param>
void StateMachineGo(StateMachine_t* sm, SMItem_t* next)
{
if(next == NULL)return;
@@ -54,17 +54,17 @@ void StateMachineGo(StateMachine_t* sm, SMItem_t* next)
/* 延迟状态举例
-/// @brief 延迟状态结构
+/// <summary>延迟状态结构</summary>
typedef struct
{
SMItem_t DelayItem;
- /// @brief 状态机主体,方便处理切换问题
+ /// <summary>状态机主体,方便处理切换问题</summary>
StateMachine_t* SM;
- /// @brief 延迟开始时间
+ /// <summary>延迟开始时间</summary>
Time_t Start;
- /// @brief 延时时间
+ /// <summary>延时时间</summary>
int DelayMs;
- /// @brief 延迟完成后进入的状态
+ /// <summary>延迟完成后进入的状态</summary>
SMItem_t* Next;
} SMDelay_t;
diff --git a/Core/StateMachine.h b/Core/StateMachine.h
index 1b65765..41718d4 100644
--- a/Core/StateMachine.h
+++ b/Core/StateMachine.h
@@ -6,22 +6,22 @@
typedef struct SMItem
{
- /// @brief 状态名称
+ /// <summary>状态名称</summary>
const char* Name;
- /// @brief 进入状态时执行的动作
+ /// <summary>进入状态时执行的动作</summary>
void(*Enter)(struct SMItem*, void* sm);
- /// @brief 运行状态时执行的动作
+ /// <summary>运行状态时执行的动作</summary>
void (*Run)(struct SMItem*, void* sm);
- /// @brief 退出状态时执行的动作
+ /// <summary>退出状态时执行的动作</summary>
void (*Exit)(struct SMItem*, void* sm);
}SMItem_t;
typedef struct
{
- /// @brief 当前状态
+ /// <summary>当前状态</summary>
struct SMItem* Current;
- /// @brief 下一个状态
+ /// <summary>下一个状态</summary>
struct SMItem* Next;
}StateMachine_t;