天下武功 其实都阅兵
注册技术 其实timer模块的码云我已经写了V1.0 V2.0
前面的那个SDK用的是数组!!我觉得可以统一下 用链表!!
统一:定时器周期执行一次函数----定时器执行LED-BEEP-RELAY这样---挂接ID-FUNCTION这样的函数注册
开始吧:
最开始是模块 链表的数据结构 一个一个的节点!上面的区别就是节点 是不一样的结构体
下面就是以前的timer 基本OK
#ifndef _GBASELIST_H_
#define _GBASELIST_H_
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stddef.h>//offsetof
typedef void (*func_call_back)(void);
/*****************模式1 周期性执行一次函数类似[000000000001][000000000001]这样子*************/
//节点的结构体
//因为我放弃了malloc只能参数自己携带内存 所以也对外提供节点的结构体
typedef struct
{
void *next;//下一个节点
uint8_t handle;//ID
uint8_t start;//开关
uint32_t cnt;//这个是实际计数值 每次+1 直到==下面设置值 就执行fun
uint32_t time_out;//这个是约定值 溢出值
void (*fun)(void);
}node_oncetime_type;
//操作 节点结构体的结构体
typedef struct
{
uint8_t (*creat) ( node_oncetime_type* node ,uint32_t time_out ,uint8_t start, func_call_back call_back);
uint8_t (*stop) ( uint8_t handle);
uint8_t (*start) ( uint8_t handle);
}once_time_ops_type;
//对外提供的句柄
extern once_time_ops_type timer;
//周期轮训业务 轮训链表的函数
void once_timer_list_loop( void );
#include "gbaselist.h"
static uint8_t SoncetimerTaskId = 0; //表示每个节点的标号 可以统计个数 以及 根据ID查找以小博大
static node_oncetime_type *Soncetimerhead = NULL; //链表的头结点
//遍历链表 周期loop执行
void once_timer_list_loop( void )
{
node_oncetime_type *priv = Soncetimerhead;
while( priv != NULL )
{
if( priv->start)
{
if( ++priv->cnt >= priv->time_out)
{
priv->cnt = 0;
if(priv->fun != NULL) priv->fun();
}
}
priv = priv->next;
}
}
//关闭节点 《并没有链表移除 而是用标记位 优点:方便简单 缺点:内存无法释放》
uint8_t once_timer_stop(uint8_t handle)
{
node_oncetime_type *priv = Soncetimerhead;
while( priv != NULL )
{
if( priv->handle == handle)
{
priv->start = false;
return true;
}
priv = priv->next;
}
return false;
}
//开启节点
uint8_t once_timer_start(uint8_t handle)
{
node_oncetime_type *priv = Soncetimerhead;
while( priv != NULL )
{
if( priv->handle == handle)
{
priv->start = true;
priv->cnt = 0;
return true;
}
priv = priv->next;
}
return false;
}
//一个节点添加到链表 返回它的ID
uint8_t once_timer_register( node_oncetime_type* node, uint32_t time_out ,uint8_t start, func_call_back call_back)
{
node_oncetime_type *priv;
node_oncetime_type *this;
this = node;//可以思考用malloc实现 目前这里和button一样我是自带内存
this->cnt = 0;//实际计数值
this->start = start;//开关
this->handle = ++SoncetimerTaskId;//在链表中的ID
this->time_out = time_out;//超时计数值
this->fun = call_back;//节点逻辑函数
this->next = NULL;//节点后继
if( Soncetimerhead == NULL)
{
Soncetimerhead = this;//第一次 实例化head
}
else
{
priv = Soncetimerhead;
while( priv->next != NULL ) priv = priv->next;//第一次以后:尾插
priv->next = this;
}
printf("new oncetimer handle=%d\r\n",SoncetimerTaskId);
return (this->handle);
}
once_time_ops_type timer =
{
.creat = once_timer_register,
.stop = once_timer_stop ,
.start = once_timer_start,
};
下面开始兼容第二个结构体!
typedef void (*fc)(void);
/*****************模式2 函数A函数B周期性循环执行类似[AAAAABBBBB][AAAAABBBBB]这样子*************/
//节点的结构体
typedef struct
{
uint8_t handle;//ID
uint8_t start; //节点功能开关
uint32_t setcnt;//设定的次数 比如鸣叫2次
uint32_t realCnt;//实际的次数 比如当前叫第1次
uint32_t RTime;//实际的计数值
uint32_t ATime;//设定的A计数值
uint32_t BTime;//设定的B计数值
fc funA;//[0-A之间的函数]
fc funB;//[A-B之间的函数]
void *next;//下一个节点
}node_twinkle_type;
//操作 节点结构体的结构体
//操作节点的函数的结构体
typedef struct
{
uint8_t (*set)( void *pnode,uint8_t handle,uint8_t enable,uint8_t Cnt , uint32_t ATime ,uint32_t BTime,fc Afun,fc Bfun);
}node_twinkle_ops_type;
//对外提供的句柄
extern node_twinkle_ops_type twinkler;
//周期轮训业务 轮训链表的函数
void twinkler_list_loop( void );
//开发给别人去做
//一个实例的应用 比如你有4个LED 那么id是你控制哪一个 cnt是闪烁几次
typedef struct
{
void (*init) (void);
void (*write) (uint8_t id,uint8_t cnt);
}twinkle_app_type;
static uint8_t StwinklerTaskId = 0; //表示每个节点的标号 可以统计个数 以及 根据ID查找以小博大
static node_twinkle_type *Stwinklerhead = NULL; //链表的头结点
//对节点的实例化 也就是赋值 这就是注册!
//每次都是尾巴插入
uint8_t twinkler_set(void *node ,uint8_t handle,uint8_t enable,uint8_t Cnt , uint32_t ATime ,uint32_t BTime,fc Afun,fc Bfun)
{
node_twinkle_type * this=(node_twinkle_type *)node;
node_twinkle_type * priv;
if(this==NULL)return 0;
this->setcnt = Cnt;
this->realCnt = 0;
this->RTime = 0;
this->ATime = ATime;
this->BTime = BTime;
this->funA = Afun;
this->funB = Bfun;
this->start = enable;
if(handle == 0)//代表第一次过来 是init 不是set
{
this->handle = ++StwinklerTaskId;
this->next = NULL;
}
if( Stwinklerhead == NULL)
{
Stwinklerhead = this;//第一次 实例化head
}
else
{
priv = Stwinklerhead;
if(handle == 0)//代表第一次过来 是init 不是set
{
while( priv->next != NULL ) priv = priv->next;//尾插 为了避免一直扩大链表 把handle再次传进来
priv->next = this;
}
else
{
while( priv->next != NULL )
{
if(priv->handle == handle)//通过ID再次在链表中找到它
memcpy(priv,this,offsetof(node_twinkle_type,next));//OK 这个节点完成覆盖 因为priv->next不会被修改所以安全
//memcpy(priv,this,sizeof(node_twinkle_type));//也OK 因为this过来的时候 是死的 最后的next不会修改
printf("old twinkler this->handle=%d\r\n",this->handle);
return (this->handle);
}
}
}
printf("new twinkler handle=%d\r\n",StwinklerTaskId);
return (this->handle);
}
//遍历链表 周期loop执行
void twinkler_list_loop( void )
{
node_twinkle_type *priv = Stwinklerhead;
while( priv != NULL )
{
if( priv->start)
{
if( priv->RTime ++ < priv->ATime) //[0---A]
{
if( *priv->funA )priv->funA() ;
}
else //[A----A+B]
{
if( *priv->funB )priv->funB() ;
}
if( priv->RTime > priv->ATime + priv->BTime)//[A+B---无穷大]
{
priv->RTime = 0;
if( ++priv->realCnt >= priv->setcnt)
{
priv->start = 0;//执行约定次数以后关闭
}
}
}
priv = priv->next;
}
}
node_twinkle_ops_type twinkler =
{
.set = twinkler_set,
};
/*此后执行BEEP鸣叫2次的操作是 第一次先twinkler_set--0完成注册到链表 以后都是回传ID控制鸣叫就是再次设置*/
需要注意的就是不要重复注册
给了外部一个结构体 外部模块举例
#ifndef _twbeep_H_
#define _twbeep_H_
#include "gbaselist.h"
extern twinkle_app_type beep;
#endif
#include "main.h"
#include "twbeep.h"
node_twinkle_type twbeep;
void beepon(void) { HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8, GPIO_PIN_RESET);}
void beepoff(void){ HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8, GPIO_PIN_SET);}
void TWBEEP_init(void)
{
twinkler.set(&twbeep,0,0,0,100,200,beepon,beepoff);
}
void TWBEEP_write(uint8_t i,uint8_t num)
{
twinkler.set(&twbeep,twbeep.handle,1,num,100,200,beepon,beepoff);
}
twinkle_app_type beep=
{
.init = TWBEEP_init,
.write = TWBEEP_write,
};
现在开始做第三个注册ID FUN
/*****************模式3 ID---FUNCTION对应的钩子函数列表作为CMD的列表*************/
typedef void (*CommandCallBack)(int fd, uint8_t sn, uint16_t len, uint8_t *data);
typedef struct
{
const char *name;
const char *help;
uint8_t handle;//ID
CommandCallBack fun;
void *next;//下一个节点
}node_command_type;
typedef struct
{
int (*Register) ( node_command_type *cmds, int numCmds);
node_command_type * (*find) ( uint16_t handle);
}command_ops_type;
extern command_ops_type commer;
/*它的应用是直接在模块中自己扩展 我内部可以注册好ID-FUN以后去解析数据拿到ID就调用对应FUN*/
#endif
static uint8_t SclientCMDId = 0; //可以不要
static node_command_type * Sclienthead =NULL;
//以小博大 根据其中一个成员找出节点
node_command_type *findCmd(uint16_t handle)
{
node_command_type *priv = Sclienthead;
while( priv->next != NULL )
{
if(priv->handle == handle)//通过ID再次在链表中找到它
return priv;
}
return NULL;
}
//就是注册 都是废话 只需要 return 0;一句话
int cliRegisterCmd(node_command_type *cmd)
{
if (!cmd->name || !cmd->fun)
return -1;
node_command_type *priv ;
if( Sclienthead == NULL)
{
Sclienthead = cmd;
}
else
{
priv = Sclienthead;
while( priv->next != NULL ) priv = priv->next;
priv->next = cmd;
}
++SclientCMDId;
printf("new cliRegisterCmd handle=%d\r\n",SclientCMDId);
return (SclientCMDId);
}
//封装一层
int cliRegisterCmds(node_command_type *cmds, int numCmds)
{
int err;
for (int i = 0; i < numCmds; i++)
{
if ((err = cliRegisterCmd(cmds++)) != 0)
{
return err;
}
}
return 0;
}
command_ops_type commer =
{
.Register = cliRegisterCmds,
.find = findCmd ,
};
这个时候 你会发现 它其实是最简单那个!!!!
APP
#include "GAppCmd.h"
static void connect(int fd, uint8_t sn, uint16_t len, uint8_t *data);
static void clearCard(int fd, uint8_t sn, uint16_t len, uint8_t *data);
static node_command_type commands[] = {
{"connect", NULL, 0, connect},
{"clearCard", NULL, 1, clearCard},
};
static void connect(int fd, uint8_t sn, uint16_t len, uint8_t *data) {
}
static void clearCard(int fd, uint8_t sn, uint16_t len, uint8_t *data) {
}
void registerCmds(void) {
commer.Register(&commands[0], sizeof(commands) / sizeof(commands[0]));
}
#ifndef GAppCmd_h
#define GAppCmd_h
#include "gbasetimerlist.h"
void registerCmds(void);
#endif