Compare commits

..

3 Commits

Author SHA1 Message Date
0x1abin 8552905e23
Merge pull request #16 from Advanced-lj/master
修改拼写错误 && 格式化代码
2 years ago
Riggin ccb71779ca 【修改】timer_stop()返回值问题 && memset()参数顺序 2 years ago
Riggin 1d387e9f4c 【修改】拼写错误 && 格式化代码 2 years ago

1
.gitignore vendored

@ -1,4 +1,3 @@
.vscode
*.o
*.out
test

@ -3,7 +3,7 @@ CC = gcc
DEL = rm -rf
CFLGAS += -std=c98
CFLGAS += -std=c99
CFLAGS += -D TEST
CFLAGS += -g
@ -17,7 +17,7 @@ INC += -I$(IDIR)
TARGET = $(BIN_PATH)/test
C_SRCS += examples/test_linux.c
C_SRCS += MultiTimer.c
C_SRCS += multi_timer.c
OBJ := $(patsubst %.c,%.o,$(filter %.c,$(addprefix $(SRC_PATH)/,$(C_SRCS))))
TARGET_OBJ := $(addprefix $(OBJ_PATH)/,$(OBJ))

@ -1,82 +0,0 @@
#include "MultiTimer.h"
#include <stdio.h>
/* Timer handle list head. */
static MultiTimer* timerList = NULL;
/* Timer tick */
static PlatformTicksFunction_t platformTicksFunction = NULL;
int MultiTimerInstall(PlatformTicksFunction_t ticksFunc)
{
platformTicksFunction = ticksFunc;
return 0;
}
int MultiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData)
{
if (!timer || !callback ) {
return -1;
}
MultiTimer** nextTimer = &timerList;
/* Remove the existing target timer. */
for (; *nextTimer; nextTimer = &(*nextTimer)->next) {
if (timer == *nextTimer) {
*nextTimer = timer->next; /* remove from list */
break;
}
}
/* Init timer. */
timer->deadline = platformTicksFunction() + timing;
timer->callback = callback;
timer->userData = userData;
/* Insert timer. */
for (nextTimer = &timerList;; nextTimer = &(*nextTimer)->next) {
if (!*nextTimer) {
timer->next = NULL;
*nextTimer = timer;
break;
}
if (timer->deadline < (*nextTimer)->deadline) {
timer->next = *nextTimer;
*nextTimer = timer;
break;
}
}
return 0;
}
int MultiTimerStop(MultiTimer* timer)
{
MultiTimer** nextTimer = &timerList;
/* Find and remove timer. */
for (; *nextTimer; nextTimer = &(*nextTimer)->next) {
MultiTimer* entry = *nextTimer;
if (entry == timer) {
*nextTimer = timer->next;
break;
}
}
return 0;
}
int MultiTimerYield(void)
{
MultiTimer* entry = timerList;
for (; entry; entry = entry->next) {
/* Sorted list, just process with the front part. */
if (platformTicksFunction() < entry->deadline) {
return (int)(entry->deadline - platformTicksFunction());
}
/* remove expired timer from list */
timerList = entry->next;
/* call callback */
if (entry->callback) {
entry->callback(entry, entry->userData);
}
}
return 0;
}

@ -1,83 +0,0 @@
/*
* Copyright (c) 2021 0x1abin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint64_t (*PlatformTicksFunction_t)(void);
typedef struct MultiTimerHandle MultiTimer;
typedef void (*MultiTimerCallback_t)(MultiTimer* timer, void* userData);
struct MultiTimerHandle {
MultiTimer* next;
uint64_t deadline;
MultiTimerCallback_t callback;
void* userData;
};
/**
* @brief Platform ticks function.
*
* @param ticksFunc ticks function.
* @return int 0 on success, -1 on error.
*/
int MultiTimerInstall(PlatformTicksFunction_t ticksFunc);
/**
* @brief Start the timer work, add the handle into work list.
*
* @param timer target handle strcut.
* @param timing Set the start time.
* @param callback deadline callback.
* @param userData user data.
* @return int 0: success, -1: fail.
*/
int MultiTimerStart(MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData);
/**
* @brief Stop the timer work, remove the handle off work list.
*
* @param timer target handle strcut.
* @return int 0: success, -1: fail.
*/
int MultiTimerStop(MultiTimer* timer);
/**
* @brief Check the timer expried and call callback.
*
* @return int The next timer expires.
*/
int MultiTimerYield(void);
#ifdef __cplusplus
}
#endif
#endif

@ -4,38 +4,52 @@
MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
## 使用方法
1. 配置系统时间基准接口,安装定时器驱动;
1.在multi_timer.h中配置定时器tick时钟频率即1个tick代表N毫秒钟
```c
uint64_t PlatformTicksGetFunc(void)
{
/* Platform implementation */
}
```
/*
It means 1 tick for 1ms.
Your can configurate for your tick time such as 5ms/10ms and so on.
*/
#define CFG_TIMER_1_TICK_N_MS 1
```
MultiTimerInstall(PlatformTicksGetFunc);
2.先申请一个定时器管理handle
```
struct Timer timer1;
```
2. 实例化一个定时器对象;
3.初始化定时器对象注册定时器回调处理函数设置延迟启动时间ms循环定时触发时间
```c
MultiTimer timer1;
```
timer_init(struct Timer* handle, void(*timeout_cb)(void *arg), uint32_t timeout, uint32_t repeat);
```
3. 设置定时时间,超时回调处理函数, 用户上下指针,启动定时器;
4.启动定时器
```c
int MultiTimerStart(&timer1, uint64_t timing, MultiTimerCallback_t callback, void* userData);
```
timer_start(&timer1);
```
4. 在主循环调用定时器后台处理函数
5.设置1ms的硬件定时器循环调用 *timer_ticks()* 以提供时间基准
```c
int main(int argc, char *argv[])
```
void HAL_SYSTICK_Callback(void)
{
timer_ticks();
}
```
6.在主循环调用定时器后台处理函数
```
int main()
{
...
while(1) {
...
MultiTimerYield();
timer_loop();
}
}
```
@ -43,59 +57,49 @@ int main(int argc, char *argv[])
## 功能限制
1.定时器的时钟频率直接影响定时器的精确度尽可能采用1ms/5ms/10ms这几个精度较高的tick;
2.定时器的回调函数内不应执行耗时操作,否则可能因占用过长的时间,导致其他定时器无法正常超时;
2.定义应用定时器时,超时时间应合理设置,不应过大或过小,否则可能导致定时器超时时间不精准;
3.定时器的回调函数内不应执行耗时操作否则可能因占用过长的时间导致其他定时器无法正常超时一般来说若干个tick的时间是可以接受的
3.由于定时器的回调函数是在 MultiTimerYield 内执行的,需要注意栈空间的使用不能过大,否则可能会导致栈溢出。
4.由于定时器的回调函数是在timer_loop内执行的,需要注意栈空间的使用不能过大,否则可能会导致栈溢出。
## Examples
见example目录下的测试代码main.c为普通平台测试demotest_linux.c为linux平台的测试demo。
```c
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include "MultiTimer.h"
```
#include "multi_timer.h"
MultiTimer timer1;
MultiTimer timer2;
MultiTimer timer3;
struct Timer timer1;
struct Timer timer2;
uint64_t PlatformTicksGetFunc(void)
void timer1_callback(void *arg)
{
struct timespec current_time;
clock_gettime(CLOCK_MONOTONIC, &current_time);
return (uint64_t)((current_time.tv_sec * 1000) + (current_time.tv_nsec / 1000000));
printf("timer1 timeout!\r\n");
}
void exampleTimer1Callback(MultiTimer* timer, void *userData)
void timer2_callback(void *arg)
{
printf("exampleTimer1Callback-> %s.\r\n", (char*)userData);
MultiTimerStart(timer, 1000, exampleTimer1Callback, userData);
printf("timer2 timeout!\r\n");
}
void exampleTimer2Callback(MultiTimer* timer, void *userData)
int main()
{
printf("exampleTimer2Callback-> %s.\r\n", (char*)userData);
}
timer_init(&timer1, timer1_callback, 1000, 1000); //1s loop
timer_start(&timer1);
void exampleTimer3Callback(MultiTimer* timer, void *userData)
{
printf("exampleTimer3Callback-> %s.\r\n", (char*)userData);
MultiTimerStart(timer, 4567, exampleTimer3Callback, userData);
}
int main(int argc, char *argv[])
{
MultiTimerInstall(PlatformTicksGetFunc);
MultiTimerStart(&timer1, 1000, exampleTimer1Callback, "1000ms CYCLE timer");
MultiTimerStart(&timer2, 5000, exampleTimer2Callback, "5000ms ONCE timer");
MultiTimerStart(&timer3, 3456, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE timer");
timer_init(&timer2, timer2_callback, 50, 0); //50ms delay
timer_start(&timer2);
while(1) {
MultiTimerYield();
timer_loop();
}
}
void HAL_SYSTICK_Callback(void)
{
timer_ticks(); //1ms ticks
}
```

@ -0,0 +1,34 @@
#include "multi_timer.h"
struct Timer timer1;
struct Timer timer2;
void timer1_callback(void *arg)
{
printf("timer1 timeout! arg: %p\r\n", arg);
}
void timer2_callback(void *arg)
{
printf("timer2 timeout! arg: %p\r\n", arg);
}
int main(void)
{
timer_init(&timer1, timer1_callback, 1000, 1000, NULL); //1s loop
timer_start(&timer1);
timer_init(&timer2, timer2_callback, 50, 0, NULL); //50ms delay
timer_start(&timer2);
while(1) {
timer_loop();
}
return 0;
}
void HAL_SYSTICK_Callback(void)
{
timer_ticks(); //1ms ticks
}

@ -1,45 +1,92 @@
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include "../MultiTimer.h"
#include <stdarg.h>
#include <string.h>
MultiTimer timer1;
MultiTimer timer2;
MultiTimer timer3;
#include "../multi_timer.h"
uint64_t PlatformTicksGetFunc(void)
#define LOG_TIMESTAMP_FORMAT "[%Y-%m-%d %H:%M:%S]"
#define LOG_TIMESTAMP_LEN 21
#define MS_TIMESTAMP_LEN 5
int32_t printf_timestamp(const char *msg, ...)
{
struct timespec current_time;
clock_gettime(CLOCK_MONOTONIC, &current_time);
return (uint64_t)((current_time.tv_sec * 1000) + (current_time.tv_nsec / 1000000));
char content[1024] = {0};
time_t time_write;
struct tm tm_Log;
struct timeval t;
uint32_t len = 0;
va_list vl_list;
time_write = time(NULL);
localtime_r(&time_write, &tm_Log);
strftime((char *)&content[len], sizeof(content) - len - 1, LOG_TIMESTAMP_FORMAT, &tm_Log);
len = strlen(&content[len]);
/* .msec] */
gettimeofday(&t, NULL);
len--; // min a ']' char
snprintf((char*)&content[len], sizeof(content) - len, ".%03d]", (int)(t.tv_usec / 1000));
len += MS_TIMESTAMP_LEN;
va_start(vl_list, msg);
vsnprintf((char *)&content[len], sizeof(content) - len - 1, (const char *)msg, vl_list);
va_end(vl_list);
printf("%s", content);
return 0;
}
void exampleTimer1Callback(MultiTimer* timer, void *userData)
void signalHandler(int signo)
{
switch(signo)
{
printf("[%012ld] Timer:%p callback-> %s.\r\n", PlatformTicksGetFunc(), timer, (char*)userData);
MultiTimerStart(timer, 1000, exampleTimer1Callback, userData);
case SIGALRM:
timer_ticks();
//printf_timestamp("Caught the SIGALRM signal every 1ms !\n");
break;
}
}
struct Timer timer1;
struct Timer timer2;
void exampleTimer2Callback(MultiTimer* timer, void *userData)
void timer1_callback(void *arg)
{
printf("[%012ld] Timer:%p callback-> %s.\r\n", PlatformTicksGetFunc(), timer, (char*)userData);
printf_timestamp("timer1 timeout! arg: %p\r\n", arg);
}
void exampleTimer3Callback(MultiTimer* timer, void *userData)
void timer2_callback(void *arg)
{
printf("[%012ld] Timer:%p callback-> %s.\r\n", PlatformTicksGetFunc(), timer, (char*)userData);
MultiTimerStart(timer, 4567, exampleTimer3Callback, userData);
printf_timestamp("timer2 timeout! arg: %p\r\n", arg);
}
int main(int argc, char *argv[])
int main(void)
{
MultiTimerInstall(PlatformTicksGetFunc);
printf_timestamp("%s start ...\r\n", __func__);
signal(SIGALRM, signalHandler);
MultiTimerStart(&timer1, 1000, exampleTimer1Callback, "1000ms CYCLE timer");
MultiTimerStart(&timer2, 5000, exampleTimer2Callback, "5000ms ONCE timer");
MultiTimerStart(&timer3, 3456, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE timer");
struct itimerval new_value, old_value;
new_value.it_value.tv_sec = 0; // should be 0x00 !!!
new_value.it_value.tv_usec = 1; // non-zero is OK !!!
new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_usec = 1000 * CFG_TIMER_1_TICK_N_MS; // 1ms
setitimer(ITIMER_REAL, &new_value, &old_value);
timer_init(&timer1, timer1_callback, 4000, 1000, &timer1); // start timer after 4s
timer_start(&timer1);
timer_init(&timer2, timer2_callback, 0, 5000, &timer2); // start timer right now
timer_start(&timer2);
while(1) {
MultiTimerYield();
/* Maybe some sleep time is needed to avoid running CPU all the time. */
timer_loop();
}
return 0;
}

@ -0,0 +1,118 @@
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#include <stdio.h>
#include "multi_timer.h"
//timer handle list head.
static struct Timer* head_handle = NULL;
//Timer ticks
//static uint32_t _timer_ticks = (1 << 32)- 1000; // only for test tick clock overflow
static uint32_t _timer_ticks = 0;
/**
* @brief Initializes the timer struct handle.
* @param handle: the timer handle struct.
* @param timeout_cb: timeout callback.
* @param timeout: delay to start the timer.
* @param repeat: repeat interval time.
* @param arg: the input argument for timeout_cb fucntion.
* @retval None
*/
void timer_init(struct Timer* handle, void (*timeout_cb)(void *arg), \
uint32_t timeout, uint32_t repeat, void *arg)
{
// memset(handle, 0, sizeof(struct Timer));
handle->timeout_cb = timeout_cb;
handle->timeout = timeout;
handle->repeat = repeat;
handle->cur_ticks = _timer_ticks;
handle->cur_expired_time = handle->timeout;
handle->arg = arg;
//printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u, timeout: %u\r\n",
// handle->cur_ticks, handle->cur_expired_time, _timer_ticks, timeout);
}
/**
* @brief Start the timer work, add the handle into work list.
* @param handle: target handle struct.
* @retval 0: succeed. -1: already exist.
*/
int timer_start(struct Timer* handle)
{
struct Timer* target = head_handle;
while(target) {
if(target == handle) {
return -1; //already exist.
}
target = target->next;
}
handle->next = head_handle;
head_handle = handle;
return 0;
}
/**
* @brief Stop the timer work, remove the handle off work list.
* @param handle: target handle struct.
* @retval 0: succeed. -1: timer not exist.
*/
int timer_stop(struct Timer* handle)
{
struct Timer** curr;
for(curr = &head_handle; *curr;) {
struct Timer* entry = *curr;
if(entry == handle) {
*curr = entry->next;
//free(entry);
return 0; // found specified timer
} else {
curr = &entry->next;
}
}
return -1;
}
/**
* @brief main loop.
* @param None.
* @retval None
*/
void timer_loop(void)
{
struct Timer* target;
for(target = head_handle; target; target = target->next) {
/*
More detail on tick-clock overflow, please see https://blog.csdn.net/szullc/article/details/115332326
*/
if(_timer_ticks - target->cur_ticks >= target->cur_expired_time) {
//printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u\r\n",
// target->cur_ticks, target->cur_expired_time, _timer_ticks);
if(target->repeat == 0) {
timer_stop(target);
} else {
target->cur_ticks = _timer_ticks;
target->cur_expired_time = target->repeat;
}
target->timeout_cb(target->arg);
}
}
}
/**
* @brief background ticks, timer repeat invoking interval nms.
* @param None.
* @retval None
*/
void timer_ticks(void)
{
_timer_ticks += CFG_TIMER_1_TICK_N_MS;
}

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_
#include <stdint.h>
#include <stddef.h>
/*
It means 1 tick for 1ms.
Your can configurate for your tick time such as 5ms/10ms and so on.
*/
#define CFG_TIMER_1_TICK_N_MS 1
typedef struct Timer {
uint32_t cur_ticks; /* Record current timer start tick */
uint32_t cur_expired_time; /* Record current timer expired time */
uint32_t timeout; /* Delay (xx ms) time to start timer */
uint32_t repeat; /* Timer interval expired time (xx ms) */
void * arg; /* Input argument for timeout_cb function */
void (*timeout_cb)(void *arg); /* Timer expired callback function */
struct Timer* next; /* Pointer to next timer */
} Timer;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes the timer struct handle.
* @param handle: the timer handle struct.
* @param timeout_cb: timeout callback.
* @param timeout: delay to start the timer.
* @param repeat: repeat interval time.
* @param arg: the input argument for timeout_cb fucntion.
* @retval None
*/
void timer_init(struct Timer* handle, void(*timeout_cb)(void *arg), \
uint32_t timeout, uint32_t repeat, void *arg);
/**
* @brief Start the timer work, add the handle into work list.
* @param handle: target handle struct.
* @retval 0: succeed. -1: already exist.
*/
int timer_start(struct Timer* handle);
/**
* @brief Stop the timer work, remove the handle off work list.
* @param handle: target handle struct.
* @retval 0: succeed. -1: timer not exist.
*/
int timer_stop(struct Timer* handle);
/**
* @brief background ticks, timer repeat invoking interval nms.
* @param None.
* @retval None
*/
void timer_ticks(void);
/**
* @brief main loop.
* @param None.
* @retval None
*/
void timer_loop(void);
#ifdef __cplusplus
}
#endif
#endif
Loading…
Cancel
Save