1. 修改成最小堆定时器

This commit is contained in:
coffee 2026-04-07 21:07:40 +08:00
parent 74e9b455fc
commit 2f9faedb8d
2 changed files with 380 additions and 172 deletions

View File

@ -1,7 +1,7 @@
/**
* : 2025-03-08
* : coffee
* : , 使, HTIMER_MAX
* : ,
*/
@ -10,13 +10,16 @@
#include <stdint.h>
#include "HList.h"
// 无效值
#ifndef HTIMER_INVALID
#define HTIMER_INVALID (-1)
#endif
// 定时器长度/索引类型,方便统一修改
typedef uint8_t HTimerLen_t;
#define HTIMER_LEN_MAX UINT8_MAX
// 检查添加定时任务超出限制后进入死循环, 方便调试
#ifdef HTIMER_CHECK_LOOP
#define HTIMER_CHECK_INVALID_LOOP
@ -36,26 +39,30 @@ typedef enum
typedef void (*HTimerCallType)();
typedef int16_t HTimer_t;
///< 注册的定时器信息, 定义为数组, 数量由外部控制
///< 定时器信息
typedef struct HTimerInfo {
uint32_t flags : 1; ///< 定时器标志, eTimerFlags
uint32_t enable : 2; ///< 定时器使能
uint32_t curr : 1; ///< 当前回调者
uint32_t duration : 28; ///< 定时触发时长, 毫秒为计数单元
uint32_t lastTime; ///< 上次触发时间
HTimerCallType call; ///< 定时触发函数
uint32_t flags : 1; ///< 定时器标志, eHTimerFlags
uint32_t curr : 1; ///< 当前回调者
uint32_t duration : 28; ///< 定时触发时长, 毫秒为计数单元
volatile uint8_t state; ///< 定时器状态 (内部使用, 原子操作)
HTimerLen_t heapIndex; ///< 堆索引, HTIMER_LEN_MAX 表示不在堆中
HTimerLen_t heapMem; ///< 堆内存, 提供给最小堆使用
uint32_t lastTime; ///< 上次触发时间
HTimerCallType call; ///< 定时触发函数
#if HTIMER_USE_USERDATA
long userData; ///< 用户数据
long userData; ///< 用户数据
#endif
HList node; ///< 定时器节点
uint8_t id; ///< 定时器ID
} HTimerInfo;
///< 定时器注册信息
typedef struct TimeRegisterInfo {
HList workNode; ///< 工作节点
HTimerInfo *timers; ///< 定时器信息
uint8_t schedu : 1; ///< 需要重新调度工作队列
uint8_t len : 7; ///< 定时器个数
HTimerInfo *timers; ///< 定时器信息数组
HTimerLen_t heapSize; ///< 堆当前大小
HTimerLen_t len; ///< 定时器个数
volatile uint8_t schedu; ///< 需要重新调度 (原子操作)
} TimeRegisterInfo;
///< 初始化毫秒定时器, 需要传递获取毫秒的函数
@ -65,16 +72,16 @@ void HTimerInitMs(uint32_t (*func)(void));
uint32_t HTimerGetMs();
/**
* @brief ()
* @param info
* @brief
* @param info
* @param len
*/
void HTimerInitRegister(TimeRegisterInfo *info, uint8_t len);
void HTimerInitRegister(TimeRegisterInfo *info, HTimerLen_t len);
/**
* @brief ()
* @brief
* @param id ID
* @param info ,
* @param info
* @param infoLen
* @return 1 0
*/
@ -100,9 +107,9 @@ long HTimerGetUserData(HTimer_t index);
long HTimerGetCurrCallUserData(uint8_t id);
#else
static inline void HTimerSetUserData(HTimer_t index, long data) {}
static inline long HTimerGetUserData(HTimer_t index) { return 0; }
static inline long HTimerGetCurrCallUserData(uint8_t id) { return 0; }
static inline void HTimerSetUserData(HTimer_t index, long data) { (void)index; (void)data; }
static inline long HTimerGetUserData(HTimer_t index) { (void)index; return 0; }
static inline long HTimerGetCurrCallUserData(uint8_t id) { (void)id; return 0; }
#endif
#endif //__H_TIMER_H__

View File

@ -1,4 +1,8 @@
/**
* : 2025-03-08
* : coffee
* : , , /线
*/
#include "HTimer.h"
#include "HDLog.h"
@ -9,13 +13,68 @@
#define LogD(...)
#endif
// ==================== 原子操作支持 ====================
#if defined(__GNUC__) || defined(__clang__)
// STM32/GD32/ESP32 都支持 GCC 扩展
// 使用 __atomic_* 系列函数,提供明确的内存序语义
static inline int htimer_cas(volatile uint8_t *ptr, uint8_t oldv, uint8_t newv) {
return __atomic_compare_exchange_n(ptr, &oldv, newv, 0, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
}
static inline void htimer_store(volatile uint8_t *ptr, uint8_t val) {
__atomic_store_n(ptr, val, __ATOMIC_RELEASE);
}
#define HTIMER_CAS(ptr, oldv, newv) htimer_cas(ptr, oldv, newv)
#define HTIMER_STORE(ptr, val) htimer_store(ptr, val)
#define HTIMER_BARRIER() __atomic_thread_fence(__ATOMIC_SEQ_CST)
#define HTIMER_ATOMIC_OR(ptr, val) __atomic_fetch_or(ptr, val, __ATOMIC_RELEASE)
#define HTIMER_ATOMIC_XCHG(ptr, val) __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL)
#define HTIMER_ATOMIC_LOAD(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define HTIMER_RELEASE_FENCE() __atomic_thread_fence(__ATOMIC_RELEASE)
#define HTIMER_ACQUIRE_FENCE() __atomic_thread_fence(__ATOMIC_ACQUIRE)
#elif defined(_MSC_VER)
#include <intrin.h>
#define HTIMER_CAS(ptr, oldv, newv) (_InterlockedCompareExchange8((volatile char*)(ptr), (char)(newv), (char)(oldv)) == (char)(oldv))
#define HTIMER_STORE(ptr, val) (*(ptr) = (val))
#define HTIMER_BARRIER() _ReadWriteBarrier()
#define HTIMER_ATOMIC_OR(ptr, val) _InterlockedOr8((volatile char*)(ptr), (char)(val))
#define HTIMER_ATOMIC_XCHG(ptr, val) _InterlockedExchange8((volatile char*)(ptr), (char)(val))
#define HTIMER_ATOMIC_LOAD(ptr) (*(volatile uint8_t*)(ptr))
#define HTIMER_RELEASE_FENCE() _ReadWriteBarrier()
#define HTIMER_ACQUIRE_FENCE() _ReadWriteBarrier()
#else
#pragma message("HTimer Not use atomic ops")
static inline int htimer_cas_simple(volatile uint8_t *ptr, uint8_t oldv, uint8_t newv) {
if (*ptr == oldv) { *ptr = newv; return 1; }
return 0;
}
static inline uint8_t htimer_xchg_simple(volatile uint8_t *ptr, uint8_t newv) {
uint8_t old = *ptr; *ptr = newv; return old;
}
#define HTIMER_CAS(ptr, oldv, newv) htimer_cas_simple(ptr, oldv, newv)
#define HTIMER_STORE(ptr, val) (*(ptr) = (val))
#define HTIMER_BARRIER() ((void)0)
#define HTIMER_ATOMIC_OR(ptr, val) (*(ptr) |= (val))
#define HTIMER_ATOMIC_XCHG(ptr, val) htimer_xchg_simple(ptr, val)
#define HTIMER_ATOMIC_LOAD(ptr) (*(ptr))
#define HTIMER_RELEASE_FENCE() ((void)0)
#define HTIMER_ACQUIRE_FENCE() ((void)0)
#endif
// 定时器内部状态
typedef enum {
kTimerUnused = 0, ///< 未使用
kTimerAdding, ///< 添加中 (单核中断安全: 初始化字段期间)
kTimerActive, ///< 活跃状态
kTimerDelete ///< 待删除
} eHTimerState;
static uint32_t (*GetCurrentMs)(void);
#define CHECK_VALUE (0x0FFFFFFF)
#define CREATE_INDEX(id, index) ((id << 8) | index)
#define GET_ID(index) ((index >> 8) & 0xFF)
#define GET_INDEX(index) (index & 0xFF)
#define HEAP_INVALID_INDEX (HTIMER_LEN_MAX)
struct __attribute__((packed)) TimerInfo {
TimeRegisterInfo *info;
@ -24,54 +83,125 @@ struct __attribute__((packed)) TimerInfo {
static struct TimerInfo sInfo;
static void InsertWorkNode(uint8_t id, HList *node) {
HTimerInfo *info = HLIST_ENTRY(node, HTimerInfo, node);
const uint32_t triggerTime = info->lastTime + info->duration;
HList *entry = NULL;
// ==================== 最小堆操作 ====================
// 堆使用 timers[i].heapMem 存储堆位置 i 处的定时器索引
// 注意:堆操作在 HTimerRun 中单线程执行,无需加锁
HLIST_FOR_EACH(entry, &sInfo.info[id].workNode) {
HTimerInfo *nodeInfo = HLIST_ENTRY(entry, HTimerInfo, node);
if ((nodeInfo->lastTime + nodeInfo->duration) < triggerTime) {
continue;
#define HEAP_AT(reg, heapIdx) ((reg)->timers[heapIdx].heapMem)
#define HEAP_SET(reg, heapIdx, timerIdx) ((reg)->timers[heapIdx].heapMem = (timerIdx))
static inline HTimerInfo* getTimer(TimeRegisterInfo *reg, int heapIdx)
{
return &reg->timers[HEAP_AT(reg, heapIdx)];
}
static void heapSwap(TimeRegisterInfo *reg, int a, int b)
{
HTimerLen_t ta = HEAP_AT(reg, a);
HTimerLen_t tb = HEAP_AT(reg, b);
HEAP_SET(reg, a, tb);
HEAP_SET(reg, b, ta);
reg->timers[ta].heapIndex = b;
reg->timers[tb].heapIndex = a;
}
static void heapUp(TimeRegisterInfo *reg, int i)
{
while (i > 0) {
int p = (i - 1) >> 1;
HTimerInfo *ti = getTimer(reg, i);
HTimerInfo *tp = getTimer(reg, p);
uint32_t iTime = ti->lastTime + ti->duration;
uint32_t pTime = tp->lastTime + tp->duration;
int32_t diff = (int32_t)(iTime - pTime);
if (diff > 0) {
break;
}
HListAddTail(node, entry);
if (diff == 0 && HEAP_AT(reg, i) > HEAP_AT(reg, p)) {
break;
}
heapSwap(reg, i, p);
i = p;
}
}
static void heapDown(TimeRegisterInfo *reg, int i)
{
int size = reg->heapSize;
while (1) {
int l = i * 2 + 1;
int r = l + 1;
int s = i;
if (l < size) {
HTimerInfo *tl = getTimer(reg, l);
HTimerInfo *ts = getTimer(reg, s);
int32_t diff = (int32_t)((tl->lastTime + tl->duration) - (ts->lastTime + ts->duration));
if (diff < 0 || (diff == 0 && HEAP_AT(reg, l) < HEAP_AT(reg, s))) {
s = l;
}
}
if (r < size) {
HTimerInfo *tr = getTimer(reg, r);
HTimerInfo *ts = getTimer(reg, s);
int32_t diff = (int32_t)((tr->lastTime + tr->duration) - (ts->lastTime + ts->duration));
if (diff < 0 || (diff == 0 && HEAP_AT(reg, r) < HEAP_AT(reg, s))) {
s = r;
}
}
if (s == i) {
break;
}
heapSwap(reg, i, s);
i = s;
}
}
static void heapPush(TimeRegisterInfo *reg, HTimerLen_t timerIdx)
{
if (reg->heapSize >= reg->len) {
return;
}
HListAddTail(node, entry);
HTimerLen_t i = reg->heapSize++;
HEAP_SET(reg, i, timerIdx);
reg->timers[timerIdx].heapIndex = i;
heapUp(reg, i);
}
static void CallTimer(uint8_t id, HList *node) {
if (id >= sInfo.infoLen) {
LogD("error id[%d]", id);
return ;
static HTimerLen_t heapPop(TimeRegisterInfo *reg)
{
if (reg->heapSize == 0) {
return HEAP_INVALID_INDEX;
}
HTimerInfo *info = HLIST_ENTRY(node, HTimerInfo, node);
// 检查是不是已经删除的定时器
if (info->enable == 0) {
return ;
HTimerLen_t ret = HEAP_AT(reg, 0);
reg->timers[ret].heapIndex = HEAP_INVALID_INDEX;
if (--reg->heapSize > 0) {
HEAP_SET(reg, 0, HEAP_AT(reg, reg->heapSize));
reg->timers[HEAP_AT(reg, 0)].heapIndex = 0;
heapDown(reg, 0);
}
if (info->flags == kHTimerOnce) {
info->enable = 0;
}
info->curr = 1;
if (info->call) {
info->call();
}
info->curr = 0;
info->lastTime = GetCurrentMs();
if (info->enable) {
// 定时器还活跃, 需要重新调度回工作队列
sInfo.info[id].schedu = 1;
}
return ret;
}
static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call, eHTimerFlags flags) {
// ==================== 定时器操作 ====================
static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call, eHTimerFlags flags)
{
if (!GetCurrentMs) {
LogD("GetCurrentMs not init");
return HTIMER_INVALID;
@ -87,198 +217,272 @@ static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call,
return HTIMER_INVALID;
}
sInfo.info[id].schedu = 1;
for (uint16_t i = 0; i < sInfo.info[id].len; ++i) {
if (sInfo.info[id].timers[i].enable) {
TimeRegisterInfo *reg = &sInfo.info[id];
uint32_t now = GetCurrentMs();
// 原子地查找并占用空闲槽位
for (HTimerLen_t i = 0; i < reg->len; ++i) {
HTimerInfo *t = &reg->timers[i];
// 第一步CAS 原子占用kTimerUnused -> kTimerAdding
// 单核中断安全即使中断发生HTimerRun 也不会处理 kTimerAdding 状态
if (!HTIMER_CAS(&t->state, kTimerUnused, kTimerAdding)) {
continue;
}
// 防中断导致数据重叠
sInfo.info[id].timers[i].enable = 1;
if (sInfo.info[id].timers[i].enable != 1) {
continue;
}
sInfo.info[id].timers[i].duration = duration;
sInfo.info[id].timers[i].lastTime = GetCurrentMs();
sInfo.info[id].timers[i].call = call;
sInfo.info[id].timers[i].flags = flags;
// 成功占用槽位,设置其他字段
#if HTIMER_USE_USERDATA
sInfo.info[id].timers[i].userData = 0;
t->userData = 0;
#endif
sInfo.info[id].timers[i].enable = 2;
t->duration = duration;
t->lastTime = now;
t->call = call;
t->flags = flags;
t->heapIndex = HEAP_INVALID_INDEX;
HTIMER_RELEASE_FENCE(); // 确保上述写入在状态变更前完成
// 第二步kTimerAdding -> kTimerActive标记初始化完成
HTIMER_STORE(&t->state, kTimerActive);
// 标记需要调度
HTIMER_ATOMIC_OR(&reg->schedu, 1);
return CREATE_INDEX(id, i);
}
// 槽位满,尝试紧急回收已删除的定时器
for (HTimerLen_t i = 0; i < reg->len; ++i) {
HTimerInfo *t = &reg->timers[i];
// 原子地将 kTimerDelete 转为 kTimerUnused
if (!HTIMER_CAS(&t->state, kTimerDelete, kTimerUnused)) {
continue;
}
// 回收成功,再次尝试占用
if (HTIMER_CAS(&t->state, kTimerUnused, kTimerAdding)) {
#if HTIMER_USE_USERDATA
t->userData = 0;
#endif
t->duration = duration;
t->lastTime = now;
t->call = call;
t->flags = flags;
t->heapIndex = HEAP_INVALID_INDEX;
HTIMER_RELEASE_FENCE();
HTIMER_STORE(&t->state, kTimerActive);
HTIMER_ATOMIC_OR(&reg->schedu, 1);
return CREATE_INDEX(id, i);
}
}
LogD("timers full, id[%d], duration[%d], flags[%d]", id, duration, flags);
return HTIMER_INVALID;
}
void HTimerInitMs(uint32_t (*func)(void)) {
void HTimerInitMs(uint32_t (*func)(void))
{
GetCurrentMs = func;
}
uint32_t HTimerGetMs() {
uint32_t HTimerGetMs()
{
if (!GetCurrentMs) {
return 0;
}
return GetCurrentMs();
}
void HTimerInitRegister(TimeRegisterInfo *info, uint8_t len)
void HTimerInitRegister(TimeRegisterInfo *info, HTimerLen_t len)
{
memset(info, 0, sizeof(*info) * len);
sInfo.info = info;
sInfo.infoLen = len;
for (uint8_t i = 0; i < len; ++i) {
HListInit(&info[i].workNode);
}
}
uint8_t HTimerRegisterTimerInfo(uint8_t id, HTimerInfo *info, uint16_t infoLen) {
uint8_t HTimerRegisterTimerInfo(uint8_t id, HTimerInfo *info, uint16_t infoLen)
{
if (id >= sInfo.infoLen) {
LogD("error id[%d], max[%d]", id, sInfo.infoLen);
return 0;
}
if (infoLen > 255) {
LogD("infoLen too large, max 255");
return 0;
}
memset(info, 0, sizeof(*info) * infoLen);
sInfo.info[id].timers = info;
sInfo.info[id].len = infoLen;
for (uint16_t i = 0; i < infoLen; ++i) {
info[i].id = id;
HListInit(&info[i].node);
TimeRegisterInfo *reg = &sInfo.info[id];
reg->timers = info;
reg->len = (HTimerLen_t)infoLen;
reg->heapSize = 0;
for (HTimerLen_t i = 0; i < infoLen; ++i) {
info[i].heapIndex = HEAP_INVALID_INDEX;
}
return 1;
}
void HTimerRun(uint8_t id) {
if (!GetCurrentMs) {
return ;
void HTimerRun(uint8_t id)
{
if (!GetCurrentMs || id >= sInfo.infoLen) {
return;
}
if (id >= sInfo.infoLen) {
return ;
}
TimeRegisterInfo *reg = &sInfo.info[id];
uint32_t now = GetCurrentMs();
do {
if (sInfo.info[id].schedu == 0) {
break;
// schedu 阶段:只有 HTimerRun 修改堆,单线程安全
// 使用 acquire-release 语义确保看到其他线程的写入
while (HTIMER_ATOMIC_XCHG(&reg->schedu, 0)) {
HTIMER_ACQUIRE_FENCE(); // 确保看到 AddTimerData 中的写入
// 1. 清理堆中已删除的定时器
for (HTimerLen_t i = reg->heapSize; i > 0;) {
i--;
HTimerLen_t tIdx = HEAP_AT(reg, i);
HTimerInfo *t = &reg->timers[tIdx];
if (HTIMER_ATOMIC_LOAD(&t->state) == kTimerDelete) {
HEAP_SET(reg, i, HEAP_AT(reg, --reg->heapSize));
t->heapIndex = HEAP_INVALID_INDEX;
t->state = kTimerUnused;
HTIMER_BARRIER();
if (i < reg->heapSize) {
heapDown(reg, i);
}
}
}
// 清空工作队列, 重新添加
HListInit(&sInfo.info[id].workNode);
for (uint16_t i = 0; i < sInfo.info[id].len; ++i) {
if (sInfo.info[id].timers[i].enable != 2) {
// 2. 清理不在堆中的已删除定时器 + 添加活跃定时器
for (HTimerLen_t i = 0; i < reg->len; i++) {
HTimerInfo *t = &reg->timers[i];
uint8_t state = HTIMER_ATOMIC_LOAD(&t->state);
if (state == kTimerDelete) {
t->state = kTimerUnused;
continue;
}
HListInit(&sInfo.info[id].timers[i].node);
InsertWorkNode(id, &sInfo.info[id].timers[i].node);
if (state == kTimerActive && t->heapIndex == HEAP_INVALID_INDEX) {
heapPush(reg, i);
}
}
} while (0);
// 检查是否有任务
if (HListEmpty(&sInfo.info[id].workNode)) {
return ;
}
HList readyNode;
HListInit(&readyNode);
// 工作队列按触发时间有序, 只需要连续取出队头的就绪任务
while (!HListEmpty(&sInfo.info[id].workNode)) {
HTimerInfo *info = HLIST_FIRST_ENTRY(&sInfo.info[id].workNode, HTimerInfo, node);
uint32_t diff = GetCurrentMs() - info->lastTime;
uint32_t timeDuration = info->duration;
if (diff < timeDuration) {
// 执行到期的定时器
while (reg->heapSize > 0) {
HTimerLen_t tIdx = HEAP_AT(reg, 0);
HTimerInfo *t = &reg->timers[tIdx];
if (HTIMER_ATOMIC_LOAD(&t->state) == kTimerDelete) {
heapPop(reg);
t->state = kTimerUnused;
t->heapIndex = HEAP_INVALID_INDEX;
continue;
}
uint32_t triggerTime = t->lastTime + t->duration;
if ((int32_t)(now - triggerTime) < 0) {
break;
}
HListMoveTail(&info->node, &readyNode);
}
heapPop(reg);
// 执行就绪队列
while (!HListEmpty(&readyNode)) {
HList *node = HListPop(&readyNode);
CallTimer(id, node);
t->curr = 1;
HTIMER_BARRIER();
if (t->call) {
t->call();
}
t->curr = 0;
HTIMER_BARRIER();
if (HTIMER_ATOMIC_LOAD(&t->state) != kTimerActive) {
continue;
}
t->lastTime = now;
if (t->flags == kHTimerLoop) {
heapPush(reg, tIdx);
} else {
t->state = kTimerDelete;
HTIMER_ATOMIC_OR(&reg->schedu, 1);
}
}
}
HTimer_t HTimerAdd(uint8_t id, uint32_t ms, HTimerCallType call, eHTimerFlags flags) {
HTimer_t HTimerAdd(uint8_t id, uint32_t ms, HTimerCallType call, eHTimerFlags flags)
{
#ifdef HTIMER_CHECK_INVALID_LOOP
HTimer_t result = AddTimerData(id, ms, call, flags);
if (result == HTIMER_INVALID) {
while (1);
}
if (result == HTIMER_INVALID) { while (1); }
return result;
#else
return AddTimerData(id, ms, call, flags);
#endif
}
void HTimerRemove(HTimer_t index) {
void HTimerRemove(HTimer_t index)
{
if (index == HTIMER_INVALID) {
return ;
return;
}
const uint8_t id = GET_ID(index);
index = GET_INDEX(index);
uint8_t id = GET_ID(index);
uint8_t i = GET_INDEX(index);
if (id >= sInfo.infoLen) {
LogD("error id[%d]", id);
return ;
return;
}
if (index < 0 || index >= sInfo.info[id].len) {
LogD("error index[%d]", index);
return ;
TimeRegisterInfo *reg = &sInfo.info[id];
if (i >= reg->len) {
return;
}
sInfo.info[id].timers[index].enable = 0;
sInfo.info[id].schedu = 1;
HTimerInfo *t = &reg->timers[i];
// 原子设置状态
uint8_t oldState;
do {
oldState = t->state;
if (oldState == kTimerUnused) {
return; // 已经删除
}
} while (!HTIMER_CAS(&t->state, oldState, kTimerDelete));
// 标记需要调度
HTIMER_ATOMIC_OR(&reg->schedu, 1);
}
#if HTIMER_USE_USERDATA
void HTimerSetUserData(HTimer_t index, long data)
{
if (index == HTIMER_INVALID) {
return ;
return;
}
const uint8_t id = GET_ID(index);
index = GET_INDEX(index);
if (id >= sInfo.infoLen) {
LogD("error id[%d]", id);
return ;
uint8_t id = GET_ID(index);
uint8_t i = GET_INDEX(index);
if (id >= sInfo.infoLen || i >= sInfo.info[id].len) {
return;
}
if (index < 0 || index >= sInfo.info[id].len) {
LogD("error index[%d]", index);
return ;
}
sInfo.info[id].timers[index].userData = data;
sInfo.info[id].timers[i].userData = data;
}
long HTimerGetUserData(HTimer_t index)
{
if (index == HTIMER_INVALID) {
if (index == HTIMER_INVALID) {
return 0;
}
const uint8_t id = GET_ID(index);
index = GET_INDEX(index);
if (id >= sInfo.infoLen) {
LogD("error id[%d]", id);
uint8_t id = GET_ID(index);
uint8_t i = GET_INDEX(index);
if (id >= sInfo.infoLen || i >= sInfo.info[id].len) {
return 0;
}
if (index < 0 || index >= sInfo.info[id].len) {
LogD("error index[%d]", index);
return 0;
}
return sInfo.info[id].timers[index].userData;
return sInfo.info[id].timers[i].userData;
}
long HTimerGetCurrCallUserData(uint8_t id)
@ -286,16 +490,13 @@ long HTimerGetCurrCallUserData(uint8_t id)
if (id >= sInfo.infoLen) {
return 0;
}
for (uint16_t i = 0; i < sInfo.info[id].len; ++i) {
if (sInfo.info[id].timers[i].curr == 0) {
continue;
TimeRegisterInfo *reg = &sInfo.info[id];
for (HTimerLen_t i = 0; i < reg->len; ++i) {
if (reg->timers[i].curr) {
return reg->timers[i].userData;
}
return sInfo.info[id].timers[i].userData;
}
return 0;
}
#endif // HTIMER_USE_USERDATA
#endif