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 == 1static 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; //初始计数值为0tBitmapInit(&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 == 1tHooksTaskSwitch(currentTask, nextTask);
#endiftTaskSwitch();//任务切换函数}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 == 1checkCpuUsage();//检查cpu使用率
#endiftTaskExitCritical(status);#if TINYOS_ENABLE_TIMER == 1tTimerModuleTickNotify();//对定时器模块的tick通知
#endif#if TINYOS_ENABLE_HOOKS == 1tHooksSysTick();
#endiftTaskSched();//调度函数
}#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;//取出计数值给MaxCountidleCount = 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;
}
#endiftTask tTaskIdle;//空闲任务
tTaskStack idleTaskEnv[TINYOS_IDLETASK_STACK_SIZE]; //空闲任务的堆栈/* 空闲任务具体内容 */
void idleTaskEntry(void *param)
{tTaskSchedDisable();//关闭调度锁,防止初始化应用任务切换到任务中运行tInitApp();#if TINYOS_ENABLE_TIMER == 1tTimerInitTask();
#endiftSetSysTickPeriod(TINYOS_SYSTICK_MS);//初始化#if TINYOS_ENABLE_CPUUSAGE_STAT == 1//时钟同步,开始测量是时钟节拍刚开始发生时,而不是两个时钟节拍之间的时间cpuUsageSyncWithSystick();
#endiffor(;;){/* 特殊代码块 */uint32_t status = tTaskEnterCritical();idleCount++;tTaskExitCritical(status);#if TINYOS_ENABLE_HOOKS == 1tHooksCpuIdle();
#endif}
}int main(void)
{tTaskSchedInit(); //初始化调度锁tTaskDelayedInit(); //初始化延时队列#if TINYOS_ENABLE_TIMER == 1tTimerModuleInit(); //初始化定时器模块
#endiftTimerTickInit(); //初始化tickCount#if TINYOS_ENABLE_CPUUSAGE_STAT == 1initCpuUsageStat(); //初始化cpu统计
#endiftTaskInit(&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); //堆栈空间清0stackTop = 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; //初始化计数器为0task->prio = prio; //初始化优先级task->state = TINYOS_TASK_STATE_RDY; //任务状态初始化为就绪态task->suspendCount = 0; //任务挂起计数器为0task->clean = (void (*)(void *))0; //清理函数为空task->cleanParam = (void *)0; //清理函数参数为空task->requestDeleteFlag = 0; //删除请求标记为0tNodeInit(&(task->delayNode)); //延时结点初始化tNodeInit(&(task->linkNode)); //链接结点初始化tTaskSchedRdy(task); //链接结点插入就绪表#if TINYOS_ENABLE_HOOKS == 1tHooksTaskInit(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);
}