Hooks扩展
Hooks,即钩子函数,用于在某些内核代码中插入一个占位。当执行到该位置时,执行自定义的功能代码,避免直接修改原始的内核代码。
在内核外部,填充该函数的实现,不必修改空闲任务的代码。
tHooks.c
#include "tinyOS.h"
#if TINYOS_ENABLE_HOOKS == 1
/* 空闲任务钩子函数 */
void tHooksCpuIdle(void)
{
}
/* systick发生钩子函数 */
void tHooksSysTick(void)
{
}
/* 任务切换钩子函数 */
void tHooksTaskSwitch(tTask *from, tTask *to)
{
}
/* 任务初始化钩子函数 */
void tHooksTaskInit(tTask *task)
{
}
#endif
tHooks.h
#ifndef __THOOKS_H
#define __THOOKS_H
#include "tTask.h"
void tHooksCpuIdle(void);
void tHooksSysTick(void);
void tHooksTaskSwitch(tTask *from, tTask *to);
void tHooksTaskInit(tTask *task);
#endif
tConfig.h
#ifndef __TCONFIG_H
#define __TCONFIG_H
#define TINYOS_PRO_COUNT 32 //优先级数量
#define TINYOS_SLICE_MAX 10 //任务时间片大小度,最小单元是一个systick周期10ms
#define TINYOS_IDLETASK_STACK_SIZE 1024 //空闲任务堆栈大小
#define TINYOS_TIMERTASK_STACK_SIZE 1024 //定时器任务堆栈大小
#define TINYOS_TIMERTASK_PRIO 1 //定时器任务优先级,不能和空闲任务相同
#define TINYOS_SYSTICK_MS 10 //SYSTICK
/* 控制开关 */
/* 计数信号量 */
#define TINYOS_ENABLE_SEM 0
/* 互斥信号量 */
#define TINYOS_ENABLE_MUTEX 0
/* 事件标志组 */
#define TINYOS_ENABLE_FLAGGROUP 0
/* 邮箱 */
#define TINYOS_ENABLE_MBOX 0
/* 存储块 */
#define TINYOS_ENABLE_MEMBLOCK 0
/* 软定时器 */
#define TINYOS_ENABLE_TIMER 0
/* CPU统计 */
#define TINYOS_ENABLE_CPUUSAGE_STAT 0
/* Hooks函数 */
#define TINYOS_ENABLE_HOOKS 1
#endif
main.c
#include "tinyOS.h"
#include "ARMCM3.h"
tTask *currentTask; //指示当前运行任务的指针
tTask *nextTask; //指向下一个任务的指针
tTask *idleTask; //空闲任务
tBitmap taskPrioBitmap; //优先级位图
tList taskTable[TINYOS_PRO_COUNT]; //任务数组列表
uint8_t schedLockCount; //调度锁计数器
tList tTaskDelayedList; //延时队列
uint32_t tickCount; //统计时钟节拍发生次数
uint32_t idleCount; //特殊代码块执行计数器
uint32_t idleMaxCount; //最大计数值
#if TINYOS_ENABLE_CPUUSAGE_STAT == 1
static void initCpuUsageStat(void);
static void checkCpuUsage(void);
static void cpuUsageSyncWithSystick(void);
#endif
/* 查找优先级位图函数 */
tTask *tTaskHighestReady(void)
{
uint32_t highestPrio = tBitmaoFirstSet(&taskPrioBitmap);
tNode *node = tListFirst(&taskTable[highestPrio]);//取出优先级队列第一个结点
return tNodeParent(node, tTask, linkNode);
}
/* 调度锁初始化函数 */
void tTaskSchedInit(void)
{
schedLockCount = 0; //初始计数值为0
tBitmapInit(&taskPrioBitmap); //对bitmap初始化
for(int i = 0; i < TINYOS_PRO_COUNT; i++) //初始化优先级数组的各个列表项
{
tListInit(&taskTable[i]);
}
}
/* 上锁函数(禁止调度函数) */
void tTaskSchedDisable(void)
{
uint32_t status = tTaskEnterCritical();
//schedLockCount是全局变量需要临界区保护
if(schedLockCount < 255)//schedLockCount是8位的,防止溢出
{
schedLockCount++;
}
tTaskExitCritical(status);
}
/* 解锁函数(使能调度函数) */
void tTaskSchedEnable(void)
{
uint32_t status = tTaskEnterCritical();
if(schedLockCount > 0)
{
if(--schedLockCount == 0)
{
tTaskSched();//执行调度函数
}
}
tTaskExitCritical(status);
}
/* 任务就绪(插入就绪表) */
void tTaskSchedRdy(tTask *task)
{
tListAddFirst(&(taskTable[task->prio]), &(task->linkNode)); //将链接结点加入所在优先级队列
tBitmapSet(&taskPrioBitmap, task->prio); //对位图置1,就绪表中设置任务就绪
}
/* 任务非就绪(移出就绪表) */
//将任务设置为非就绪状态
void tTaskSchedUnRdy(tTask *task)
{
tListRemove(&(taskTable[task->prio]), &(task->linkNode));
if(tListCount(&taskTable[task->prio]) == 0)//判断列表中是否还有其他任务
{
tBitmapClear(&taskPrioBitmap, task->prio); //没有其他任务,位图位清零
}
}
/* 优先级队列移除任务 */
void tTaskSchedRemove(tTask *task)
{
tListRemove(&(taskTable[task->prio]), &(task->linkNode));
if(tListCount(&taskTable[task->prio]) == 0)//判断列表中是否还有其他任务
{
tBitmapClear(&taskPrioBitmap, task->prio); //没有其他任务,位图位清零
}
}
/* 调度函数 */
//决定CPU在哪两个任务之间运行,采用什么规则,怎么分配
void tTaskSched(void)
{
tTask *tempTask;
uint32_t status = tTaskEnterCritical();
//判断调度器是否上锁
if(schedLockCount > 0)//上锁
{
tTaskExitCritical(status);//退出
return;
}
tempTask = tTaskHighestReady();//获取最高优先级需要占用CPU运行的任务
if(tempTask != currentTask)//最高优先级任务与当前任务不同
{
nextTask = tempTask;
#if TINYOS_ENABLE_HOOKS == 1
tHooksTaskSwitch(currentTask, nextTask);
#endif
tTaskSwitch();//任务切换函数
}
tTaskExitCritical(status);
}
/* 延时队列初始化 */
void tTaskDelayedInit()
{
tListInit(&tTaskDelayedList);//初始化延时链表
}
/* 任务挂起(插入延时队列) */
void tTimeTaskWait(tTask *task, uint32_t ticks)
{
task->delayTicks = ticks;
tListAddLast(&tTaskDelayedList, &(task->delayNode));//任务插入队列尾部
task->state |= TINYOS_TASK_STATE_DELAYED;
}
/* 任务唤醒(移出延时队列) */
void tTimeTaskWakeUp(tTask *task)
{
tListRemove(&tTaskDelayedList, &(task->delayNode));
task->state &= ~TINYOS_TASK_STATE_DELAYED;//清除延时标志位
}
/* 延时队列移除任务 */
void tTimeTaskRemove(tTask *task)
{
tListRemove(&tTaskDelayedList, &(task->delayNode));
}
/* tickCount初始化函数 */
void tTimerTickInit(void)
{
tickCount = 0;
}
/* 时钟节拍处理函数 */
void tTaskSystemTickHandler(void)
{
tNode *node;
uint32_t status = tTaskEnterCritical();
//扫描延时队列
for(node = tTaskDelayedList.headNode.nextNode; node != &(tTaskDelayedList.headNode); node = node->nextNode)
{
tTask *task = tNodeParent(node, tTask, delayNode);//获取任务结构
if(--task->delayTicks == 0)//判断任务有没有延时到
{
if(task->waitEvent)//判断任务是否在等待事件
{
tEventRemoveTask(task, (void *)0, tErrorTimeout);//从事件控制块中移除
}
tTimeTaskWakeUp(task);//从延时队列中移除
tTaskSchedRdy(task);//插入就绪表
}
}
if(--currentTask->slice == 0)//当前任务时间片是否已用完
{
if(tListCount(&taskTable[currentTask->prio]) > 0)//还有其他任务
{
//切换轮转
tListRemoveFirst(&taskTable[currentTask->prio]);
tListAddLast(&taskTable[currentTask->prio], &(currentTask->linkNode));
currentTask->slice = TINYOS_SLICE_MAX;//时间片重新赋值
}
}
tickCount++;
#if TINYOS_ENABLE_CPUUSAGE_STAT == 1
checkCpuUsage();//检查cpu使用率
#endif
tTaskExitCritical(status);
#if TINYOS_ENABLE_TIMER == 1
tTimerModuleTickNotify();//对定时器模块的tick通知
#endif
#if TINYOS_ENABLE_HOOKS == 1
tHooksSysTick();
#endif
tTaskSched();//调度函数
}
#if TINYOS_ENABLE_CPUUSAGE_STAT == 1
static float cpuUsage;
static uint32_t enableCpuUsageState;
/* 初始化cpu统计函数 */
static void initCpuUsageStat(void)
{
idleCount = 0;
idleMaxCount = 0;
cpuUsage = 0.0f;
enableCpuUsageState = 0;
}
/* 检查cpu使用率函数 */
static void checkCpuUsage(void)
{
//判断是否同步
if(enableCpuUsageState == 0)
{
enableCpuUsageState = 1;
tickCount = 0;
return;
}
if(tickCount == TICKS_PER_SEC)//恰好运行到一秒
{
idleMaxCount = idleCount;//取出计数值给MaxCount
idleCount = 0;
tTaskSchedEnable();
}
else if(tickCount % TICKS_PER_SEC == 0)//每隔一秒检查CPU利用率
{
cpuUsage = 100 - (idleCount * 100.0 / idleMaxCount);
idleCount = 0;
}
}
/* 检查cpu使用率与系统时钟节拍同步辅助函数 */
static void cpuUsageSyncWithSystick(void)
{
//不断对标志位进行检查,等待与系统时钟节拍同步
while(enableCpuUsageState == 0)
{
;;
}
}
/* cpu获取函数 */
float tCpuUsageGet(void)
{
float usage = 0;
uint32_t status = tTaskEnterCritical();
usage = cpuUsage;
tTaskExitCritical(status);
return usage;
}
#endif
tTask tTaskIdle;//空闲任务
tTaskStack idleTaskEnv[TINYOS_IDLETASK_STACK_SIZE]; //空闲任务的堆栈
/* 空闲任务具体内容 */
void idleTaskEntry(void *param)
{
tTaskSchedDisable();//关闭调度锁,防止初始化应用任务切换到任务中运行
tInitApp();
#if TINYOS_ENABLE_TIMER == 1
tTimerInitTask();
#endif
tSetSysTickPeriod(TINYOS_SYSTICK_MS);//初始化
#if TINYOS_ENABLE_CPUUSAGE_STAT == 1
//时钟同步,开始测量是时钟节拍刚开始发生时,而不是两个时钟节拍之间的时间
cpuUsageSyncWithSystick();
#endif
for(;;)
{
/* 特殊代码块 */
uint32_t status = tTaskEnterCritical();
idleCount++;
tTaskExitCritical(status);
#if TINYOS_ENABLE_HOOKS == 1
tHooksCpuIdle();
#endif
}
}
int main(void)
{
tTaskSchedInit(); //初始化调度锁
tTaskDelayedInit(); //初始化延时队列
#if TINYOS_ENABLE_TIMER == 1
tTimerModuleInit(); //初始化定时器模块
#endif
tTimerTickInit(); //初始化tickCount
#if TINYOS_ENABLE_CPUUSAGE_STAT == 1
initCpuUsageStat(); //初始化cpu统计
#endif
tTaskInit(&tTaskIdle, idleTaskEntry, (void *)0, TINYOS_PRO_COUNT - 1, idleTaskEnv, TINYOS_IDLETASK_STACK_SIZE);//创建空闲任务
idleTask = &tTaskIdle;//空闲任务赋值
nextTask = tTaskHighestReady();//初始运行任务指向就绪表中优先级最高的任务
tTaskRunFirst();//切换到第0个任务运行
return 0;
//执行tTaskRunFirst函数后,CPU的控制权切换到任务里运行
//任务里是for循环会一直在任务里运行
//切换到另一个函数里面也是for循环
//永远不会返回
}
tTask.c
#include "tinyOS.h"
/* 任务初始化函数 */
//参数:tTask结构的指针,任务入口函数的地址,传递给任务的参数地址,优先级,堆栈起始地址,堆栈大小
//任务初始运行时,会把栈里的内容依次弹出来,恢复到内核寄存器中。
void tTaskInit(tTask *task, void(*entry)(void *), void *param, uint32_t prio, tTaskStack *stack, uint32_t size)
{
uint32_t *stackTop;//指向堆栈末端
task->stackBase = stack; //堆栈起始位置
task->stackSize = size; //堆栈大小
memset(stack, 0, size); //堆栈空间清0
stackTop = stack + size / sizeof(tTaskStack);//堆栈起始位置+堆栈大小(除堆栈单元的大小)
//初始化具体的堆栈内容
//传递堆栈的末端地址,内核本身的堆栈增长方式是满递减方式增长的,先进行递减操作
*(--stackTop) = (unsigned long)(1 << 24); //xPSR,设置T标志位
*(--stackTop) = (unsigned long)entry; //R15(PC),程序入口函数
*(--stackTop) = (unsigned long)0x14; //R14(LR),未用
*(--stackTop) = (unsigned long)0x12; //R12,未用
*(--stackTop) = (unsigned long)0x3; //R3,未用
*(--stackTop) = (unsigned long)0x2; //R2,未用
*(--stackTop) = (unsigned long)0x1; //R1,未用
*(--stackTop) = (unsigned long)param; //R0,程序的入口参数,函数第一个参数存入R0
*(--stackTop) = (unsigned long)0x11; //R11,未用
*(--stackTop) = (unsigned long)0x10; //R10,未用
*(--stackTop) = (unsigned long)0x9; //R9,未用
*(--stackTop) = (unsigned long)0x8; //R8,未用
*(--stackTop) = (unsigned long)0x7; //R7,未用
*(--stackTop) = (unsigned long)0x6; //R6,未用
*(--stackTop) = (unsigned long)0x5; //R5,未用
*(--stackTop) = (unsigned long)0x4; //R4,未用
task->slice = TINYOS_SLICE_MAX; //时间片初始值是最大值
task->stack = stackTop; //保存最终的值
task->delayTicks = 0; //初始化计数器为0
task->prio = prio; //初始化优先级
task->state = TINYOS_TASK_STATE_RDY; //任务状态初始化为就绪态
task->suspendCount = 0; //任务挂起计数器为0
task->clean = (void (*)(void *))0; //清理函数为空
task->cleanParam = (void *)0; //清理函数参数为空
task->requestDeleteFlag = 0; //删除请求标记为0
tNodeInit(&(task->delayNode)); //延时结点初始化
tNodeInit(&(task->linkNode)); //链接结点初始化
tTaskSchedRdy(task); //链接结点插入就绪表
#if TINYOS_ENABLE_HOOKS == 1
tHooksTaskInit(task);
#endif
}
/* 任务挂起函数 */
void tTaskSuspend(tTask *task)
{
uint32_t status = tTaskEnterCritical();
if(!(task->state & TINYOS_TASK_STATE_DELAYED))//任务不在延时状态
{
if(++task->suspendCount <= 1)//对挂起计数器++后,挂起计数器是第一次挂起
{
task->state |= TINYOS_TASK_SYATE_SUSPEND;//任务为挂起态
tTaskSchedUnRdy(task);//将任务从挂起就绪列表中移除
if(task == currentTask)//判断任务是否是当前任务
{
tTaskSched();
}
}
}
tTaskExitCritical(status);
}
/* 任务恢复函数 */
void tTaskWakeUp(tTask *task)
{
uint32_t status = tTaskEnterCritical();
if(task->state & TINYOS_TASK_SYATE_SUSPEND)//任务在挂起状态
{
if(--task->suspendCount == 0)
{
task->state &= ~TINYOS_TASK_SYATE_SUSPEND;//清除挂起态
tTaskSchedRdy(task);//将任务插入就绪列表
tTaskSched();
}
}
tTaskExitCritical(status);
}
/* 资源清理回调函数 */
void tTaskSetCleanCallFunc(tTask *task, void (*clean)(void *param), void *param)
{
task->clean = clean;
task->cleanParam = param;
}
/* 强制删除函数 */
void tTaskForceDelete(tTask *task)
{
uint32_t status = tTaskEnterCritical();
if(task->state & TINYOS_TASK_STATE_DELAYED)//任务处于延时状态
{
tTimeTaskRemove(task);
}
else if(!(task->state & TINYOS_TASK_SYATE_SUSPEND))//任务不处于挂起状态
{
//任务在运行或就绪态
tTaskSchedRemove(task);
}
if(task->clean)
{
task->clean(task->cleanParam);
}
if(currentTask == task)//任务是当前任务
{
tTaskSched();
}
tTaskExitCritical(status);
}
/* 请求删除函数 */
void tTaskRequestDelete(tTask *task)
{
uint32_t status = tTaskEnterCritical();
task->requestDeleteFlag = 1;
tTaskExitCritical(status);
}
/* 检查删除请求函数 */
uint8_t tTaskIsRequestedDelete(void)
{
uint8_t delete;
uint32_t states = tTaskEnterCritical();
delete = currentTask->requestDeleteFlag;
tTaskExitCritical(states);
return delete;
}
/* 删除任务自己函数 */
void tTaskDeleteSelf(void)
{
uint32_t states = tTaskEnterCritical();
//任务处于运行态
tTaskSchedRemove(currentTask);
if(currentTask->clean)
{
currentTask->clean(currentTask->cleanParam);
}
tTaskSched();
tTaskExitCritical(states);
}
/* 任务状态查询函数 */
void tTaskGetInfo(tTask *task, tTaskInfo *info)
{
uint32_t *stackEnd;//堆栈末端指针
uint32_t states = tTaskEnterCritical();
info->delayTicks = task->delayTicks;
info->prio = task->prio;
info->slice = task->slice;
info->state = task->state;
info->suspendCount = task->suspendCount;
info->stackSize = task->stackSize;
info->stackFree = 0;
stackEnd = task->stackBase;//堆栈向下生长,stackBase处于堆栈空间的低地址
while((*stackEnd++ == 0) && (stackEnd <= task->stackBase + task->stackSize / sizeof(tTaskStack)))//再判断一下这个位置有没有超出堆栈空间
{
info->stackFree++;
}
info->stackFree *= sizeof(tTaskStack);//单元数转为字节数
tTaskExitCritical(states);
}