/* 2 ************************************************************************************* 3 * uC/OS-II实时控制内核 4 * 主要的包含文件 5 * --事件标志组管理-- 6 * 文 件: OS_FLAG.C 事件标志组代码 7 * 作 者: Jean J. Labrosse 8 * 中文注解: 钟常慰 zhongcw @ 126.com 整理:lin-credible 译注版本:1.0 请尊重原版内容 9 ************************************************************************************* 10 */ 11 12 #ifndef OS_MASTER_FILE //是否已定义OS_MASTER_FILE主文件 13 #include "INCLUDES.H" //包含"includes.h"文件,部分C语言头文件的汇总打包文件 14 #endif //定义结束 15 16 //条件编译:UCOS版本>= 251 且 OS_FLAG_EN 允许产生事件标志程序代码 且 最大事件标志>0 17 #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) 18 /* 19 ************************************************************************************** 20 * 局部函数原型 21 ************************************************************************************** 22 */ 23 24 static void OS_FlagBlock(OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, 25 OS_FLAGS flags, INT8U wait_type, INT16U timeout); 26 static BOOLEAN OS_FlagTaskRdy(OS_FLAG_NODE *pnode, OS_FLAGS flags_rdy); 27 28 /*$PAGE*/ 29 /* 30 ************************************************************************************** 31 * 检查事件标志组 32 * 33 * 描述: 检查事件标志组中的事件标志位是置位还是清0。 34 * 应用程序可以检查任意一位是置位还是清0,也可以检查所有位是置位还是清0。 35 * 此函数于OSFlagPend()不同在于,如果需要的事件标志没有产生,那么调用该函数的任务 36 * 并不挂起。 37 * 38 * 参数: pgrp 指向事件标志组的指针。建立事件标志组时(OSFlagCreate())得到该指针。 39 * 40 * flags 指定需要检查的事件标志位。为1则检查对应位;为0则忽若对应位。 41 * 42 * wait_type 定义等待事件标志位的方式。可以分为以下4种: 43 * 44 * OS_FLAG_WAIT_CLR_ALL 所有指定事件标志位清 (0); 45 * OS_FLAG_WAIT_CLR_ANY 任意指定事件标志位清 (0); 46 * OS_FLAG_WAIT_SET_ALL 所有指定事件标志位置 (1); 47 * OS_FLAG_WAIT_SET_ANY 任意指定事件标志位置 (1)。 48 * 49 * 注意:如果需要在得到期望的事件标志后,恢复该事件标志,则可以在调用函数时 50 * ,将该参数加上一个常量OS_FLAG_CONSUME。例如,如果等待事件标志组中 51 * 任意指定事件标志位置位,并且在任意事件标志位置位后清除该位,则把参 52 * 数wait_type设置为: 53 * OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME 54 * 55 * err 指向包含错误码的变量的指针。返回的错误码可能为以下几种: 56 * OS_NO_ERR 调用成功; 57 * OS_ERR_EVENT_TYPE pgrp指针不是指向事件标志组的指针; 58 * OS_FLAG_ERR_WAIT_TYPE wait_type参数不是指定的4种方式之一; 59 * OS_FLAG_INVALID_PGRP pgrp是一个空指针; 60 * OS_FLAG_ERR_NOT_RDY 指定的事件标志没有发生。 61 * 62 * 返回: 返回事件标志组的事件标志状态 63 * 64 * 注意/警告:1、必须先建立事件标志组,然后使用; 65 * 2、如果指定的事件标志没有发生,则调用任务并不挂起。 66 *************************************************************************************** 67 */ 68 #if OS_FLAG_ACCEPT_EN > 0 //允许生成 OSFlagAccept()代码 69 // 检查事件标志组函数(标志组的指针、事件标志位、等待事件标志位的方式、错误码指针) 70 OS_FLAGS OSFlagAccept (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT8U *err) 71 { 72 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 73 OS_CPU_SR cpu_sr; 74 #endif 75 OS_FLAGS flags_cur; //定义一个"取出当前位"保存值 76 OS_FLAGS flags_rdy; //定义一个"准备完毕"含量值 77 BOOLEAN consume; //定义一个"清除"事件标志位(保存值) 78 79 80 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 81 if (pgrp == (OS_FLAG_GRP *)0) { //返回的事件标志组pgrp是一个空指针 82 *err = OS_FLAG_INVALID_PGRP; //'pgrp'不是指向事件标志组的指针 83 return ((OS_FLAGS)0); //返回0 84 } 85 if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { //当数据指针类型不是事件标志组类型 86 *err = OS_ERR_EVENT_TYPE; //'pgrp'是空指针 87 return ((OS_FLAGS)0); //返回0 88 } 89 #endif 90 if (wait_type & OS_FLAG_CONSUME) { //保存这个事件标志位在局部变量中consume 91 wait_type &= ~OS_FLAG_CONSUME; //wait_type保存这个反值 92 consume = TRUE; //"清除"事件标志位置1,需要对这个标志清0 93 } else { //否则 94 consume = FALSE; //"清除"事件标志位为0 95 } 96 /*$PAGE*/ 97 *err = OS_NO_ERR; /* Assume NO error until proven otherwise. */ 98 OS_ENTER_CRITICAL(); //打开中断 99 switch (wait_type) { //判断等待事件标志位的方式 100 case OS_FLAG_WAIT_SET_ALL: //1、如果所有指定事件标志位置1 101 flags_rdy = pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 102 if (flags_rdy == flags) { //如果取出的位的状态恰好完全符合预期的状态 103 if (consume == TRUE) { //查看是否需要对这个标志清0 104 pgrp->OSFlagFlags &= ~flags_rdy; //将任务需要等待的事件标志位置位(准备完毕) 105 } 106 } else { 107 *err = OS_FLAG_ERR_NOT_RDY; //指定的事件标志没有发生 108 } 109 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 110 OS_EXIT_CRITICAL(); //打开中断 111 break; //条件满足,则跳出此选择体 112 113 case OS_FLAG_WAIT_SET_ANY: //2、任意指定事件标志位置1 114 flags_rdy = pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 115 if (flags_rdy != (OS_FLAGS)0) { //如果指定的事件标志位中任意一个已经置位, 116 //则等待操作立刻结束,返回调用函数 117 if (consume == TRUE) { //查看是否需要对这个标志清0 118 pgrp->OSFlagFlags &= ~flags_rdy; //将任务需要等待的事件标志位置位(准备完毕) 119 } 120 } else { 121 *err = OS_FLAG_ERR_NOT_RDY; //指定的事件标志没有发生 122 } 123 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 124 OS_EXIT_CRITICAL(); //打开中断 125 break; //条件满足,则跳出此选择体 126 127 #if OS_FLAG_WAIT_CLR_EN > 0 //允许生成 Wait on Clear 事件标志代码,其实使用前两种方式即可 128 case OS_FLAG_WAIT_CLR_ALL: //3、所有指定事件标志位清0 129 flags_rdy = ~pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 130 if (flags_rdy == flags) { //如果取出的位的状态恰好完全符合预期的状态 131 if (consume == TRUE) { //查看是否需要对这个标志清0 132 pgrp->OSFlagFlags |= flags_rdy; //将任务需要等待的事件标志位清0(准备完毕) 133 } 134 } else { 135 *err = OS_FLAG_ERR_NOT_RDY; //指定的事件标志没有发生 136 } 137 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 138 OS_EXIT_CRITICAL(); //打开中断 139 break; //条件满足,则跳出此选择体 140 141 case OS_FLAG_WAIT_CLR_ANY: //4、所有指定事件标志位清0 142 flags_rdy = ~pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 143 if (flags_rdy != (OS_FLAGS)0) { //如果指定的事件标志位中任意一个已经置位 144 //则等待操作立刻结束,返回调用函数 145 if (consume == TRUE) { //查看是否需要对这个标志清0 146 pgrp->OSFlagFlags |= flags_rdy; //将任务需要等待的事件标志位清0(准备完毕) 147 } 148 } else { 149 *err = OS_FLAG_ERR_NOT_RDY; //指定的事件标志没有发生 150 } 151 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 152 OS_EXIT_CRITICAL(); //打开中断 153 break; 154 #endif 155 156 default: //以上类型全部不是 157 OS_EXIT_CRITICAL(); //打开中断 158 flags_cur = (OS_FLAGS)0; //事件标志位值清0 159 *err = OS_FLAG_ERR_WAIT_TYPE; //wait_type参数不是指定的4种方式之一 160 break; //条件满足,则跳出此选择体 161 } 162 return (flags_cur); //返回新的事件标志位值(0),并返回到调用函数 163 } 164 #endif 165 166 /*$PAGE*/ 167 /* 168 *************************************************************************************** 169 * 创建一个事件标志组 170 * 171 * 描述: 创建并初始化一个事件标志组 172 * 173 * 参数: flags 事件标志组的事件标志初值 174 * 175 * err 指向包含错误码的变量的指针。返回的错误码可能为以下几种: 176 * OS_NO_ERR 成功创建事件标志组 177 * OS_ERR_CREATE_ISR 从中断中调用OSFlagCreate()函数 178 * OS_FLAG_GRP_DEPLETED 系统没有剩余的空闲事件标志组,需要更改OS_CFG.H中 179 * 的事件标志组数目配置 180 * 181 * 返回: 如果成功创建事件标志组,则返回该事件标志组的指针; 182 * 若系统没有剩余的空闲事件标志组,则返回空指针。 183 * 184 * 注意/警告: 在使用任何事件标志组功能之前,必须使用该函数创建事件标志组。 185 **************************************************************************************** 186 */ 187 188 OS_FLAG_GRP *OSFlagCreate (OS_FLAGS flags, INT8U *err) 189 { //建立一个事件标志组(初值、错误码) 190 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 191 OS_CPU_SR cpu_sr; 192 #endif 193 OS_FLAG_GRP *pgrp; //定义一个事件标志变量 194 195 196 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行 197 *err = OS_ERR_CREATE_ISR; //返回(从中断中调用OSFlagCreate()函数)不允许 198 return ((OS_FLAG_GRP *)0); //系统没有剩余的空闲事件标志组,则返回空指针 199 } 200 OS_ENTER_CRITICAL(); //关闭中断 201 //pgrp=从系统的空闲事件标志组链表中取一个空闲的事件标志组 202 pgrp = OSFlagFreeList; 203 //如果返回一个空指针,说明系统已经没有一个空闲的事件标志组可以分配 204 if (pgrp != (OS_FLAG_GRP *)0) { 205 //分配后,调整系统空闲事件标志组链表指针,os_max_flags中 206 OSFlagFreeList = (OS_FLAG_GRP *)OSFlagFreeList->OSFlagWaitList; 207 pgrp->OSFlagType = OS_EVENT_TYPE_FLAG; //数据结构=事件标志组 208 pgrp->OSFlagFlags = flags; //事件标志初始化 209 pgrp->OSFlagWaitList = (void *)0; //等待任务链接表指针初始化为NULL 210 OS_EXIT_CRITICAL(); //打开中断 211 *err = OS_NO_ERR; //成功创建标志组 212 } else { //没有空余的事件标志组 213 OS_EXIT_CRITICAL(); //打开中断 214 *err = OS_FLAG_GRP_DEPLETED; //错误=没有空余的事件标志组 215 } 216 return (pgrp); // 返回事件标志组指针 217 } 218 219 /*$PAGE*/ 220 /* 221 ***************************************************************************************** 222 * 删除一个事件标志组 223 * 224 * 描述: 用于删除一个事件标志组。因为多任务可能会试图继续使用已经删除了的事件标志组,故调 225 * 用本函数有风险,需小心。一般在删除事件标志组之前,应该首先删除与本事件有关任务。 226 * 227 * 参数: pgrp 指向事件标志组的指针。建立事件标志组时(OSFlagCreate())得到该指针。 228 * 229 * opt 确定删除一个事件的条件值: 230 * opt == OS_DEL_NO_PEND 指明是仅在没有任务等待事件标志组时删除该事件标志组 231 * opt == OS_DEL_ALWAYS 指明不管是否有任务等待事件标志组都删除该事件标志组 232 * 如果是后者,所有等待该事件标志组的任务都被置位就绪。 233 * 234 * err 指向包含错误码的变量的指针。返回的错误码可能为以下几种之一: 235 * OS_NO_ERR 成功删除该事件标志组; 236 * OS_ERR_DEL_ISR 从中断中调用OSFlagDel()函数; 237 * OS_FLAG_INVALID_PGRP pgrp是一个空指针; 238 * OS_ERR_EVENT_TYPE pgrp不是指向事件标志组的指针; 239 * OS_ERR_INVALID_OPT opt参数不是指定的值; 240 * OS_ERR_TASK_WAITING 如果opt参数为OS_DEL_NO_PEND,那么此时有任务等待 241 * 事件标志组 242 * 243 * 返回: 如果事件标志组被删除,组则返回空指针; 244 * 如果没有删除,则仍然返回指向该事件标志组的指针。 245 * 后一种情况需要检查出错代码,找出事件标志的失败的原因 246 * 247 * 注意: 1) 需要小心,可能有其它任务正在等待该事件标志组的事件标志 248 * 2) 该函数有可能长时间关闭中断,其时间长短决定于标志组的任务个数 249 ****************************************************************************************** 250 */ 251 252 #if OS_FLAG_DEL_EN > 0 //允许生成 OSFlagDel()代码 253 //删除一个事件标志组(指针、条件值、错误值) 254 OS_FLAG_GRP *OSFlagDel (OS_FLAG_GRP *pgrp, INT8U opt, INT8U *err) 255 { 256 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 257 OS_CPU_SR cpu_sr; 258 #endif 259 BOOLEAN tasks_waiting; //任务等待条件 260 OS_FLAG_NODE *pnode; //定义标志节点 261 262 263 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行 264 *err = OS_ERR_DEL_ISR; //返回(从中断中调用OSFlagDel()函数)不允许 265 return (pgrp); //返回该事件标志组的指针 266 } 267 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 268 if (pgrp == (OS_FLAG_GRP *)0) { //返回的事件标志组pgrp是一个空指针 269 *err = OS_FLAG_INVALID_PGRP; //返回该事件标志组的指针 270 return (pgrp); 271 } 272 if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { //当数据指针类型不是事件标志组类型 273 *err = OS_ERR_EVENT_TYPE; //pgrp不是指向事件标志组的指针 274 return (pgrp); //返回该事件标志组的指针 275 } 276 #endif 277 OS_ENTER_CRITICAL(); //关闭中断 278 if (pgrp->OSFlagWaitList != (void *)0) { //是否真的有任务在等待该标志组(不是0) 279 tasks_waiting = TRUE; //有任务在等待(真) 280 } else { //否则 281 tasks_waiting = FALSE; //没有任务在等待(假) 282 } 283 switch (opt) { // 1)选择没有任务等待才删除事件标志组 284 case OS_DEL_NO_PEND: //当任务等待为假 285 if (tasks_waiting == FALSE) { //事件标志组为空闲标志组 286 //标志组为空闲事件标志 287 //标志组放回到空闲事件标志链接表 288 //空余事件标志组=当前事件标志指针 289 pgrp->OSFlagType = OS_EVENT_TYPE_UNUSED; 290 pgrp->OSFlagWaitList = (void *)OSFlagFreeList; 291 OSFlagFreeList = pgrp; 292 OS_EXIT_CRITICAL(); //打开中断 293 *err = OS_NO_ERR; //成功删除事件标志组 294 return ((OS_FLAG_GRP *)0); //成功删除事件标志组(返回0) 295 } else { //否则 296 OS_EXIT_CRITICAL(); //打开中断 297 *err = OS_ERR_TASK_WAITING; //有任务在等待 298 return (pgrp); //返回该事件标志组的指针 299 } 300 301 case OS_DEL_ALWAYS: // 2)多任务等待(全部置为就绪态) 302 pnode = pgrp->OSFlagWaitList; 303 while (pnode != (OS_FLAG_NODE *)0) { 304 OS_FlagTaskRdy(pnode, (OS_FLAGS)0); 305 pnode = pnode->OSFlagNodeNext; 306 } 307 //标志组为空闲事件标志 308 //标志组放回到空闲事件标志链接表 309 //空余事件标志组=当前事件标志指针 310 pgrp->OSFlagType = OS_EVENT_TYPE_UNUSED; 311 pgrp->OSFlagWaitList = (void *)OSFlagFreeList; 312 OSFlagFreeList = pgrp; 313 OS_EXIT_CRITICAL(); //打开中断 314 if (tasks_waiting == TRUE) { //当任务等待为假 315 OS_Sched(); //将最高就绪优先级状态任务运行(调度任务) 316 } 317 *err = OS_NO_ERR; //成功删除事件标志组 318 return ((OS_FLAG_GRP *)0); //成功删除事件标志组(返回0) 319 320 default: // 3)以上两个态度都不是 321 OS_EXIT_CRITICAL(); //打开中断 322 *err = OS_ERR_INVALID_OPT; //返回以上两种状态都不是 323 return (pgrp); //返回该事件标志组的指针 324 } 325 } 326 #endif 327 /*$PAGE*/ 328 /* 329 ****************************************************************************************** 330 * 等待事件标志组中的事件标志(WAIT ON AN EVENT FLAG GROUP) 331 * 332 * 描述: 任务等待事件标志组中的事件标志,可以是多个事件标志的不同组合方式。可以等待任 333 * 意指定事件标志位置位或清0,也可以是全部指定事件标志位置位或清0。如果任务等待 334 * 的事件标志位条件尚不满足,则任务会被挂起,直到指定的事件标志组合发生或指定的 335 * 等待时间超时。 336 * 337 * 参数: pgrp 指向事件标志组的指针。建立事件标志组时(OSFlagCreate())得到该指针。 338 * 339 * flags 指定需要检查的事件标志位。置为1,则检查对应位;置为0,则忽略对应位。 340 * 341 * wait_type 定义等待事件标志位的方式。可以定为以下几种: 342 * 343 * OS_FLAG_WAIT_CLR_ALL 所有指定事件标志位清0 ; 344 * OS_FLAG_WAIT_SET_ALL 任意指定事件标志位置1 ; 345 * OS_FLAG_WAIT_CLR_ANY 所有指定事件标志位清0 ; 346 * OS_FLAG_WAIT_SET_ANY 任意指定事件标志位置1 ; 347 * 348 * 提示: 如果需要在得到期望的事件标志后恢复该事件标志,则可以在调用该函数时,将 349 * 该参数加上一个常量OS_FLAG_CONSUME。例如,如果等待事件标志组中任意指定事 350 * 件标志位置位,并且在任意事件标志位置位后清除该位,则可以把参数wait_type 351 * 设置为: OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME 352 * 353 * timeout 以时钟节拍数目的等待超时时限。如果在这一时限得不到事件,任务将恢复执行。 354 * timeout的值为0,表示将无限期地等待事件。timeout的最大值是65535个时钟节 355 * 拍。timeout的值并不与时钟节拍同步,timeout计数器在下一个时钟节拍到来时 356 * 开始递减。在这里,所谓下一个时钟节拍,也就是立刻就到来了。 357 * 358 * err 指向错误代码的指针,出错代码为以下值之一: 359 * OS_NO_ERR 成功调用; 360 * OS_ERR_PEND_ISR 从中断中调用该函数,这是规则不允许的; 361 * OS_FLAG_INVALID_PGRP 'pgrp'不是指向事件标志组的指针; 362 * OS_ERR_EVENT_TYPE 'pgrp'是空指针 363 * OS_TIMEOUT 等待事件标志组的事件标志超时; 364 * OS_FLAG_ERR_WAIT_TYPE 'wait_type'不是指定的参数之一。 365 * 366 * OS_FLAG_CONSUME 定义常量OS_FLAG_CONSUME为0x80 367 * 368 * 返回: 如果使用了OS_FLAG_CONSUME选项,则返回清理后的事件标志组事件标志状态;否则返 369 * 回OSFlagPend()函数运行结束后的事件标志组事件标志状态;如果发生了超时,则返回0。 370 * 371 * 注意:必须首先创建事件标志组,再使用。 372 ****************************************************************************************** 373 */ 374 //等待事件标志组的事件标志位(事件组指针、需要检查的标志位、等待事件标志位的方式、允许等待 375 的时钟节拍、出错代码的时钟节拍) 376 OS_FLAGS OSFlagPend (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, 377 INT8U *err) 378 { 379 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 380 OS_CPU_SR cpu_sr; 381 #endif 382 OS_FLAG_NODE node; //定义标志节点 383 OS_FLAGS flags_cur; //定义一个"取出当前位"保存值 384 OS_FLAGS flags_rdy; //定义一个"准备完毕"含量值 385 BOOLEAN consume; //定义一个"清除"事件标志位(保存值) 386 387 388 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行 389 *err = OS_ERR_PEND_ISR; //从中断中调用该函数,这是规则不允许的 390 return ((OS_FLAGS)0); //返回0 391 } 392 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 393 if (pgrp == (OS_FLAG_GRP *)0) { //返回的事件标志组pgrp是一个空指针 394 *err = OS_FLAG_INVALID_PGRP; //'pgrp'不是指向事件标志组的指针 395 return ((OS_FLAGS)0); //返回0 396 } 397 if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { //当数据指针类型不是事件标志组类型 398 *err = OS_ERR_EVENT_TYPE; //'pgrp'是空指针 399 return ((OS_FLAGS)0); //返回0 400 } 401 #endif 402 if (wait_type & OS_FLAG_CONSUME) { //保存这个事件标志位在局部变量中consume 403 wait_type &= ~OS_FLAG_CONSUME; //wait_type保存这个反值 404 consume = TRUE; //"清除"事件标志位置1,需要对这个标志清0 405 } else { //否则 406 consume = FALSE; //"清除"事件标志位为0 407 } 408 /*$PAGE*/ 409 OS_ENTER_CRITICAL(); //打开中断 410 switch (wait_type) { //判断等待事件标志位的方式 411 case OS_FLAG_WAIT_SET_ALL: //1、如果所有指定事件标志位置1 412 flags_rdy = pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 413 if (flags_rdy == flags) { //如果取出的位的状态恰好完全符合预期的状态 414 if (consume == TRUE) { //查看是否需要对这个标志清0 415 pgrp->OSFlagFlags &= ~flags_rdy; //将任务需要等待的事件标志位置位(准备完毕) 416 } 417 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 418 OS_EXIT_CRITICAL(); //打开中断 419 *err = OS_NO_ERR; //成功调用 420 return (flags_cur); //返回新的事件标志位值,并返回到调用函数 421 } else { //如果期望的事件标志位没有置位,任务将被挂起, 422 //直到事件标志位置位或者等待超时 423 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); 424 OS_EXIT_CRITICAL(); //打开中断 425 } 426 break; //条件满足,则跳出此选择体 427 428 case OS_FLAG_WAIT_SET_ANY: //2、任意指定事件标志位置1 429 flags_rdy = pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 430 if (flags_rdy != (OS_FLAGS)0) { //如果指定的事件标志位中任意一个已经置位, 431 //则等待操作立刻结束,返回调用函数 432 if (consume == TRUE) { //查看是否需要对这个标志清0 433 pgrp->OSFlagFlags &= ~flags_rdy; //将任务需要等待的事件标志位置位(准备完毕) 434 } 435 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 436 OS_EXIT_CRITICAL(); //打开中断 437 *err = OS_NO_ERR; //成功调用 438 return (flags_cur); //返回新的事件标志位值,并返回到调用函数 439 } else { //如果期望的事件标志位没有置位,任务将被挂起, 440 //直到事件标志位置位或者等待超时 441 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); 442 OS_EXIT_CRITICAL(); //打开中断 443 } 444 break; //条件满足,则跳出此选择体 445 446 #if OS_FLAG_WAIT_CLR_EN > 0 //允许生成 Wait on Clear 事件标志代码,其实使用前两种方式即可 447 case OS_FLAG_WAIT_CLR_ALL: //3、所有指定事件标志位清0 448 flags_rdy = ~pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 449 if (flags_rdy == flags) { //如果取出的位的状态恰好完全符合预期的状态 450 if (consume == TRUE) { //查看是否需要对这个标志清0 451 pgrp->OSFlagFlags |= flags_rdy; //将任务需要等待的事件标志位清0(准备完毕) 452 } 453 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 454 OS_EXIT_CRITICAL(); //打开中断 455 *err = OS_NO_ERR; //成功调用 456 return (flags_cur); //返回新的事件标志位值,并返回到调用函数 457 } else { //如果期望的事件标志位没有置位,任务将被挂起, 458 //直到事件标志位置位或者等待超时 2008.07.29 459 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); 460 OS_EXIT_CRITICAL(); //打开中断 461 } 462 break; //条件满足,则跳出此选择体 463 464 case OS_FLAG_WAIT_CLR_ANY: //4、所有指定事件标志位清0 465 flags_rdy = ~pgrp->OSFlagFlags & flags; //取事件标志组中由flags参数指定的事件标志位 466 if (flags_rdy != (OS_FLAGS)0) { //如果指定的事件标志位中任意一个已经置位 467 //则等待操作立刻结束,返回调用函数 468 if (consume == TRUE) { //查看是否需要对这个标志清0 469 pgrp->OSFlagFlags |= flags_rdy; //将任务需要等待的事件标志位清0(准备完毕) 470 } 471 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 472 OS_EXIT_CRITICAL(); //打开中断 473 *err = OS_NO_ERR; //成功调用 474 return (flags_cur); //返回新的事件标志位值,并返回到调用函数 475 } else { //如果期望的事件标志位没有置位,任务将被挂起, 476 //直到事件标志位置位或者等待超时 477 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); 478 OS_EXIT_CRITICAL(); //打开中断 479 } 480 break; //条件满足,则跳出此选择体 481 #endif 482 483 default: //以上类型全部不是 484 OS_EXIT_CRITICAL(); //打开中断 485 flags_cur = (OS_FLAGS)0; //事件标志位值清0 486 *err = OS_FLAG_ERR_WAIT_TYPE; //'wait_type'不是指定的参数之一 487 return (flags_cur); //返回新的事件标志位值(0),并返回到调用函数 488 } 489 OS_Sched(); //调用高优先级就绪态任务运行 490 OS_ENTER_CRITICAL(); //关闭中断 491 //当这个任务恢复运行时,首先检查是因为什么原因而恢复运行的。如果任务控制块的状态表明,该任 492 //务还在等待事件标志组的事件标志,那么这个任务一定是因为等待事件标志超时而恢复运行的 493 if (OSTCBCur->OSTCBStat & OS_STAT_FLAG) { /* Have we timed-out? */ 494 //在这种情况下,调用OS_FlagUnlink()函数,把这个OS_FLAG_NODE从事件标志组的等待任务链表中 495 //删除,并且返回一个出错代码,说明发生了等待超时。这段代码只是简单的将一个OS_FLAG_NODE 496 //从一个双向链表中删除 497 OS_FlagUnlink(&node); 498 OSTCBCur->OSTCBStat = OS_STAT_RDY; //任务准备运行(准备完毕) 499 OS_EXIT_CRITICAL(); //打开中断 500 flags_cur = (OS_FLAGS)0; //事件标志位值清0 501 *err = OS_TIMEOUT; //等待事件标志组的事件标志超时 502 } else { 503 //如果任务恢复运行不是因为等待超时,那么一定是任务等待的事件标志按照预期的方式产生了,此时, 504 //根据调用OSFlagPend()时传入的是否清除事件标志的参数,对事件标志进行相应的置位或清0操作 505 if (consume == TRUE) { //查看是否需要对这个标志清0 506 switch (wait_type) { //判断等待类型 507 case OS_FLAG_WAIT_SET_ALL: //任意指定事件标志位置1 508 case OS_FLAG_WAIT_SET_ANY: //所有指定事件标志位置1 509 //将任务需要等待的事件标志位置位 510 pgrp->OSFlagFlags &= ~OSTCBCur->OSTCBFlagsRdy; 511 break; //条件满足,则跳出此选择体 512 513 #if OS_FLAG_WAIT_CLR_EN > 0 //允许生成 Wait on Clear 事件标志代码 514 case OS_FLAG_WAIT_CLR_ALL: //所有指定事件标志位清0 515 case OS_FLAG_WAIT_CLR_ANY: //指定事件标志位清0 516 //任意将任务需要等待的事件标志位清0 517 pgrp->OSFlagFlags |= OSTCBCur->OSTCBFlagsRdy; 518 break; //条件满足,则跳出此选择体 519 #endif 520 } 521 } 522 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 523 OS_EXIT_CRITICAL(); //打开中断 524 *err = OS_NO_ERR; //成功调用 525 } 526 return (flags_cur); //返回新的事件标志位值,并返回到调用函数 527 } 528 /*$PAGE*/ 529 /* 530 ****************************************************************************************** 531 * 给出设定的事件标志位(POST EVENT FLAG BIT(S)) 532 * 533 * 描述: 给出设定的事件标志位。指定的事件标志位可以设定为置位或清除。若OSFlagPost()设 534 * 置的事件标志位正好满足某个等待使劲标志组的任务,则OSFlagPost()将该任务设为就绪。 535 * 536 * 参数: pgrp 指向事件标志组的指针。建立事件标志组时(OSFlagCreate())得到该指针。 537 * 538 * flags 指定需要检查的事件标志位。如果opt参数位OS_FLAG_SET,那么事件标志组中对 539 * 应的事件标志位置位。例如,如果置位事件标志组的事件标志0、4和5,则需要把 540 * FLAGS参数设置位ox31(bit 0 是最低位)。若opt参数为OS_FLAG_CLR,那么事件标 541 * 志组中对应的事件标志为被清0。 542 * 543 * opt 表明是置位指定事件标志位(OS_FLAG_SET); 544 * 还是清0指定事件标志位(OS_FLAG_CLR)。 545 * 546 * err 指向错误代码的指针,出错代码为以下值之一: 547 * OS_NO_ERR 成功调用 548 * OS_FLAG_INVALID_PGRP 'pgrp'指针为空指针 549 * OS_ERR_EVENT_TYPE 'pgrp'指针没有指向事件标志组结构; 550 * OS_FLAG_INVALID_OPT opt不是指定的参数之一。 551 * 552 * 返回: 事件标志组的新的事件标志状态 553 * 554 * 警告: 1) 必须先创建事件标志组,然后使用; 555 * 2) 这个函数的运行时间决定于等待事件标志组的任务的数目; 556 * 3) 关闭中断的时间也取决于等待事件标志组的任务的数目。 557 ****************************************************************************************** 558 */ 559 //置位或清0事件标志组中的标志位(指针、标志位、条件值、错误码) 560 OS_FLAGS OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *err) 561 { 562 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 563 OS_CPU_SR cpu_sr; 564 #endif 565 OS_FLAG_NODE *pnode; //定义标志节点指针 566 BOOLEAN sched; //定义一个"最高就绪态运行"保存值 567 OS_FLAGS flags_cur; //定义一个"取出当前位"保存值 568 OS_FLAGS flags_rdy; //定义一个"准备完毕"含量值 569 570 571 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 572 if (pgrp == (OS_FLAG_GRP *)0) { //返回的事件标志组pgrp是一个空指针 573 *err = OS_FLAG_INVALID_PGRP; //返回的事件标志组pgrp是一个空指针 574 return ((OS_FLAGS)0); //返回0 575 } 576 if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { //当数据指针类型不是事件标志组类型 577 *err = OS_ERR_EVENT_TYPE; //'pgrp'是空指针 578 return ((OS_FLAGS)0); //返回0 579 } 580 #endif 581 /*$PAGE*/ 582 OS_ENTER_CRITICAL(); //打开中断 583 switch (opt) { //判断设定的事件标志位条件 584 case OS_FLAG_CLR: //设定为清0指定事件标志位 585 pgrp->OSFlagFlags &= ~flags; //清除事件标志 586 break; //条件满足,则跳出此选择体 587 588 case OS_FLAG_SET: //设定为置位指定事件标志位 589 pgrp->OSFlagFlags |= flags; //置位事件标志 590 break; //条件满足,则跳出此选择体 591 592 default: //如果两者都不是 593 OS_EXIT_CRITICAL(); //打开中断 594 *err = OS_FLAG_INVALID_OPT; //opt不是指定的参数之一 595 return ((OS_FLAGS)0); //返回0 596 } 597 sched = FALSE; //假定对事件标志的操作不会导致一个更高优先级的任务进入就绪态 598 pnode = pgrp->OSFlagWaitList; //保存事件标志组 599 while (pnode != (OS_FLAG_NODE *)0) { //如果有任务在等待这个事件标志组, 600 switch (pnode->OSFlagNodeWaitType) { 601 //如果等待任务链表是空的,本函数将获取当前事件志组的事件标志状态,并返回调用函数; 602 //若等待任务非空,本函数将历遍所有的OS_FLAG_NODE,以检查新设定的事件标志是否满足 603 //某个任务期待的条件。每个任务含以下四种情况: 604 case OS_FLAG_WAIT_SET_ALL: //所有指定事件标志位置1 605 flags_rdy = pgrp->OSFlagFlags & pnode->OSFlagNodeFlags; 606 //如果一个任务等待的事件标志位条件得到满足,那么这个任务将被标志为进入就绪态。 607 if (flags_rdy == pnode->OSFlagNodeFlags) { 608 //通过调用 OS_FlagTaskRdy()来进入就绪态 609 if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { 610 sched = TRUE; //这里任务等待的事件标志已经满足,任务进入就绪态, 611 //所以需要立即进入任务调度。但是并不是每检查一个OS_FLAG_NODE,就进行 常慰 612 //进行一次任务调度,而是在历遍完全部等待任务后,进行一次总的调度,所 613 //以这里将是否需要进行调度的信息保留在一个局部布尔变量sched中。 614 } 615 } 616 break; //条件满足,则跳出此选择体 617 618 case OS_FLAG_WAIT_SET_ANY: //任意指定事件标志位置1 619 flags_rdy = pgrp->OSFlagFlags & pnode->OSFlagNodeFlags; 620 if (flags_rdy != (OS_FLAGS)0) { 621 if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { 622 sched = TRUE; 623 } 624 } 625 break; 626 627 #if OS_FLAG_WAIT_CLR_EN > 0 //允许生成 Wait on Clear 事件标志代码,其实使用前两种方式即可 628 case OS_FLAG_WAIT_CLR_ALL: //所有指定事件标志位清0 629 flags_rdy = ~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags; 630 if (flags_rdy == pnode->OSFlagNodeFlags) { 631 if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { 632 sched = TRUE; 633 } 634 } 635 break; 636 637 case OS_FLAG_WAIT_CLR_ANY: //任意指定事件标志位清0 638 flags_rdy = ~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags; 639 if (flags_rdy != (OS_FLAGS)0) { 640 if (OS_FlagTaskRdy(pnode, flags_rdy) == TRUE) { 641 sched = TRUE; 642 } 643 } 644 break; 645 #endif 646 } 647 648 pnode = pnode->OSFlagNodeNext; //通过双向链表得到下一个OS_FLAG_NODE的指针 649 } 650 //当历遍等待任务列表时,中断是关闭的,这意味着OSFlagPost()函数有可能导致中断的长时 651 //间关闭,特别是在OSFlagPost()函数可能引起多任务进入就绪态时,在这种情况下,该函数 652 //的执行时间仍然是有限的,而且是可能预先确定的 653 OS_EXIT_CRITICAL(); //打开中断 654 if (sched == TRUE) { //如果发现更高优先级任务由于对事件标志的操作而进入就绪态TRUE 655 OS_Sched(); //历遍完等待任务链表后,判断是否需要进入任务调度,这可能导致一个 656 //刚刚接收到预期的事件标志而进入就绪态的更高优先级的任务开始运行 。 657 } 658 OS_ENTER_CRITICAL(); //关闭中断 659 flags_cur = pgrp->OSFlagFlags; //获取事件标志组的新的事件标志位值 660 OS_EXIT_CRITICAL(); //打开中断 661 *err = OS_NO_ERR; //成功调用 662 return (flags_cur); //返回当前事件标志组的事件标志状态 663 } 664 /*$PAGE*/ 665 /* 666 ****************************************************************************************** 667 * 查询事件标志组的当前事件标志状态(QUERY EVENT FLAG) 668 * 669 * 描述: 查询事件标志组的当前事件标志状态。在现在的版本中,该函数还不能返回等待该事件 670 * 标志组的任务列表 671 * 672 * 参数: pgrp 指向事件标志组的指针。建立事件标志组时(OSFlagCreate())得到该指针。 673 * 674 * err 指向错误代码的指针,出错代码为以下值之一: 675 * OS_NO_ERR 成功调用 676 * OS_FLAG_INVALID_PGRP 'pgrp'指针为空指针 677 * OS_ERR_EVENT_TYPE 'pgrp'指针没有指向事件标志组结构。 678 * 679 * 返回: 事件标志组的新的事件标志状态 680 * 681 * 警告: 1) 必须先创建事件标志组,然后使用; 682 * 2) 可以从中断中调用该函数。 683 * 684 * Called From: Task or ISR 685 ****************************************************************************************** 686 */ 687 688 #if OS_FLAG_QUERY_EN > 0 //允许生成 OSFlagQuery() 689 //查询事件标志组的当前事件标志状态(事件标志组的指针、错误代码的指针) 690 OS_FLAGS OSFlagQuery (OS_FLAG_GRP *pgrp, INT8U *err) 691 { 692 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 693 OS_CPU_SR cpu_sr; 694 #endif 695 OS_FLAGS flags; //定义一个"当前位"状态 696 697 698 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 699 if (pgrp == (OS_FLAG_GRP *)0) { //返回的事件标志组pgrp是一个空指针 700 *err = OS_FLAG_INVALID_PGRP; //返回的事件标志组pgrp是一个空指针 701 return ((OS_FLAGS)0); //返回0 702 } 703 if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { //当数据指针类型不是事件标志组类型 704 *err = OS_ERR_EVENT_TYPE; //'pgrp'是空指针 705 return ((OS_FLAGS)0); //返回0 706 } 707 #endif 708 OS_ENTER_CRITICAL(); //打开中断 709 flags = pgrp->OSFlagFlags; //获取事件标志组的当前的事件标志位值 710 OS_EXIT_CRITICAL(); //关闭中断 711 *err = OS_NO_ERR; //成功调用 712 return (flags); //返回当前事件标志状态 713 } 714 #endif 715 716 /*$PAGE*/ 717 /* 718 ****************************************************************************************** 719 * SUSPEND TASK UNTIL EVENT FLAG(s) RECEIVED OR TIMEOUT OCCURS 720 * 721 * 描述: 这个函数是uC/OS-II的内部函数,如果期望的事件标志位没有置位,任务将被挂起,直到事件 722 * 标志位置位或者等待超时。 723 * 此程序完成操作并将调用OSFlagBlock()的任务添加到事件标志组的等待列表中 724 * 725 * 参数: pgrp 指向事件标志组的指针。建立事件标志组时(OSFlagCreate())得到该指针。 726 * 727 * pnode is a pointer to a structure which contains data about the task waiting for 728 * event flag bit(s) to be set. 729 * 730 * flags 指定需要检查的事件标志位。如果opt参数位OS_FLAG_SET,那么事件标志组中对 731 * 应的事件标志位置位。例如,如果置位事件标志组的事件标志0、4和5,则需要把 732 * FLAGS参数设置位ox31(bit 0 是最低位)。若opt参数为OS_FLAG_CLR,那么事件标 733 * 志组中对应的事件标志为被清0。 734 * 735 * 736 * wait_type 定义等待事件标志位的方式。可以分为以下4种: 737 * 738 * OS_FLAG_WAIT_CLR_ALL 所有指定事件标志位清 (0); 739 * OS_FLAG_WAIT_CLR_ANY 任意指定事件标志位清 (0); 740 * OS_FLAG_WAIT_SET_ALL 所有指定事件标志位置 (1); 741 * OS_FLAG_WAIT_SET_ANY 任意指定事件标志位置 (1)。 742 * 743 * timeout 以时钟节拍数目的等待超时时限。如果在这一时限得不到事件,任务将恢复执行。 744 * timeout的值为0,表示将无限期地等待事件。timeout的最大值是65535个时钟节 745 * 拍。timeout的值并不与时钟节拍同步,timeout计数器在下一个时钟节拍到来时 746 * 开始递减。在这里,所谓下一个时钟节拍,也就是立刻就到来了。 747 * 748 * 返回: 无 749 * 750 * 程序在: OS_FLAG.C中OSFlagPend() 751 * 752 * 注意: 这个程序是uC/OS-II内部的,请不要调用它. 753 ****************************************************************************************** 754 755 static void OS_FlagBlock (OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, 756 INT8U wait_type, INT16U timeout) 757 { 758 OS_FLAG_NODE *pnode_next; //定义标志下一个节点(变量) 759 760 761 OSTCBCur->OSTCBStat |= OS_STAT_FLAG; //(将任务的状态字)处于FLAG状态0x20 762 OSTCBCur->OSTCBDly = timeout; /* Store timeout in task's TCB */ 763 #if OS_TASK_DEL_EN > 0 764 OSTCBCur->OSTCBFlagNode = pnode; //把标志节点保存到TCB中 765 #endif 766 pnode->OSFlagNodeFlags = flags; //保存任务等待事件标志组的指定事件标志位 767 pnode->OSFlagNodeWaitType = wait_type; //保存任务等待事件标志组的等待类型的信息 768 //把任务控制块指针保存到标志节点的任务控制块链接中 769 pnode->OSFlagNodeTCB = (void *)OSTCBCur; 770 //事件标志组对应的所有标志节点都链接在一起,保存在事件标志组的等待任务链表中 771 pnode->OSFlagNodeNext = pgrp->OSFlagWaitList; 772 pnode->OSFlagNodePrev = (void *)0; //新增的标志节点被添加到双向链表的开始端 773 pnode->OSFlagNodeFlagGrp = (void *)pgrp; 774 //事件标志组的指针被反向链接到标志节点的事件标志组指针中,当删除一个任务时,需要根据这个链接 775 //把被删除的任务从对应的事件标志组的等待任务列表删除。 776 pnode_next = pgrp->OSFlagWaitList; 777 if (pnode_next != (void *)0) { //把前一个标志节点指针链接到新添加的标志节点 778 pnode_next->OSFlagNodePrev = pnode; /* No, link in doubly linked list */ 779 } 780 pgrp->OSFlagWaitList = (void *)pnode; 781 //等待任务列表的起始指针被变更为新添加的标志节点,调用任务也不再处于就绪态 782 if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { 783 OSRdyGrp &= ~OSTCBCur->OSTCBBitY; 784 } 785 } 786 787 /*$PAGE*/ 788 /* 789 ****************************************************************************************** 790 * INITIALIZE THE EVENT FLAG MODULE 791 * 792 * 描述: This function is called by uC/OS-II to initialize the event flag module. Your application 793 * MUST NOT call this function. In other words, this function is internal to uC/OS-II. 794 * 795 * 参数: 无 796 * 797 * 返回: 无 798 * 799 * 警告: You MUST NOT call this function from your code. This is an INTERNAL function to uC/OS-II. 800 ****************************************************************************************** 801 */ 802 803 void OS_FlagInit (void) 804 { 805 #if OS_MAX_FLAGS == 1 806 OSFlagFreeList = (OS_FLAG_GRP *)&OSFlagTbl[0]; 807 OSFlagFreeList->OSFlagType = OS_EVENT_TYPE_UNUSED; 808 OSFlagFreeList->OSFlagWaitList = (void *)0; 809 #endif 810 811 #if OS_MAX_FLAGS >= 2 812 INT8U i; 813 OS_FLAG_GRP *pgrp1; 814 OS_FLAG_GRP *pgrp2; 815 816 817 pgrp1 = &OSFlagTbl[0]; 818 pgrp2 = &OSFlagTbl[1]; 819 for (i = 0; i < (OS_MAX_FLAGS - 1); i++) { /* Init. list of free EVENT FLAGS */ 820 pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED; 821 pgrp1->OSFlagWaitList = (void *)pgrp2; 822 pgrp1++; 823 pgrp2++; 824 } 825 pgrp1->OSFlagWaitList = (void *)0; 826 OSFlagFreeList = (OS_FLAG_GRP *)&OSFlagTbl[0]; 827 #endif 828 } 829 830 /*$PAGE*/ 831 /* 832 ****************************************************************************************** 833 * 使等待事件标志的任务进入就绪态 MAKE TASK READY-TO-RUN, EVENT(s) OCCURRED 834 * 835 * 描述: 这个函数是 uC/OS-II内部函数. 836 * 该处理在uC/OS-II中是一个标准过程,这个惟一的不同在于,事件标志组中当一个任务等待的 837 * 事件标志发生后,为该任务建立的OS_FLAG_NODE数据结构就没有用处了;所以这里把这个任务 838 * 的OS_FLAG_NODE数据结构从等待任务链表中删除掉,同时还会把这个OS_FLAG_NODE数据结构指 839 * 针,从该任务的事件控制块中删除掉。 钟常慰 840 * 841 * 参数: pnode 标志节点is a pointer to a structure which contains data about the task 842 * waiting forevent flag bit(s) to be set. 843 * 844 * flags_rdy contains the bit pattern of the event flags that cause the task to become 845 * ready-to-run. 846 * //定义一个"准备完毕"含量值 847 * 848 * 返回: 无 849 * 850 * 访问: 本函数在OS_FLAG.C的OSFlagsPost() 中 851 * 852 * 注意: 1) 即使任务等待的事件标志都发生了,任务已经从事件标志组的等待任务链表中被删除了,但 853 * 是这个任务可能由于其它的原因而不能进入就绪态; 854 * 2) 这个函数是uC/OS-II内部函数,你应用的时候不要调用它. 855 ****************************************************************************************** 856 */ 857 858 static BOOLEAN OS_FlagTaskRdy (OS_FLAG_NODE *pnode, OS_FLAGS flags_rdy) 859 { 860 OS_TCB *ptcb; 861 BOOLEAN sched; 862 863 864 ptcb = (OS_TCB *)pnode->OSFlagNodeTCB; // 865 ptcb->OSTCBDly = 0; 866 ptcb->OSTCBFlagsRdy = flags_rdy; 867 ptcb->OSTCBStat &= ~OS_STAT_FLAG; 868 if (ptcb->OSTCBStat == OS_STAT_RDY) { // 869 OSRdyGrp |= ptcb->OSTCBBitY; 870 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; 871 sched = TRUE; 872 } else { 873 sched = FALSE; 874 } 875 OS_FlagUnlink(pnode); 876 return (sched); 877 } 878 879 /*$PAGE*/ 880 /* 881 ****************************************************************************************** 882 * 从任务等待链表中删除 UNLINK EVENT FLAG NODE FROM WAITING LIST 883 * 884 * 描述: 这个函数是uC/OS-II内部函数,从任务等待链表中删除。 885 * 886 * 参数: pnode is a pointer to a structure which contains data about the task waiting for 887 * event flag bit(s) to be set. 888 * 889 * 返回: 无 890 * 891 * 访问: OS_FlagTaskRdy() OS_FLAG.C 892 * OSFlagPend() OS_FLAG.C 893 * OSTaskDel() OS_TASK.C 894 * 895 * 注意: 1) This function assumes that interrupts are disabled. 896 * 2) 这个函数是uC/OS-II内部函数,你应用的时候不要调用它. 897 ****************************************************************************************** 898 */ 899 //在这种情况下,调用OS_FlagUnlink()函数,把这个OS_FLAG_NODE从事件标志组的等待任务链表中 900 //删除,并且返回一个出错代码,说明发生了等待超时。这段代码只是简单的将一个OS_FLAG_NODE 901 //从一个双向链表中删除 902 void OS_FlagUnlink (OS_FLAG_NODE *pnode) 903 { 904 OS_TCB *ptcb; 905 OS_FLAG_GRP *pgrp; 906 OS_FLAG_NODE *pnode_prev; 907 OS_FLAG_NODE *pnode_next; 908 909 910 pnode_prev = pnode->OSFlagNodePrev; //定义指向链表中的后一个数据结构(链表的一个节点) 911 pnode_next = pnode->OSFlagNodeNext; //定义指向链表中的前一个数据结构(链表的一个节点) 912 if (pnode_prev == (OS_FLAG_NODE *)0) { //检查指向前一个节点的指针为NULL 913 //事件标志组的指针被反向链接到标志节点的事件标志组指针中,当删除一个任务时,需要根据 914 //这个链接把被删除的任务从对应的事件标志组的等待任务列表删除 915 pgrp = pnode->OSFlagNodeFlagGrp; 916 pgrp->OSFlagWaitList = (void *)pnode_next; 917 //如果即将被删除的节点是链表第一个节点,那么在该节点删除后,链表的指针表头指针应该指 918 //向下一个节点。 919 if (pnode_next != (OS_FLAG_NODE *)0) { 920 //如果被删除的节点确实是链接的第1个节点,那么紧接着的下一个节点的"后一个节点", 921 //这个新的头节点的"前一个节点指针"将被更新为NULL。 922 pnode_next->OSFlagNodePrev = (OS_FLAG_NODE *)0; 923 } 924 } else { 925 //如果被删除的节点不是链表中的第1个节点,那么这个节点的前一个节点的"后一个节点指针"将 926 //指向即将被删除的节点的后一个字节 927 pnode_prev->OSFlagNodeNext = pnode_next; 928 if (pnode_next != (OS_FLAG_NODE *)0) { 929 pnode_next->OSFlagNodePrev = pnode_prev; 930 //同样,这个被删除的节点的后一个节点的"前一个节点指针"也要被更新为该即将被删除节点 931 //的前一个节点。 932 } 933 } 934 ptcb = (OS_TCB *)pnode->OSFlagNodeTCB; 935 #if OS_TASK_DEL_EN > 0 936 ptcb->OSTCBFlagNode = (void *)0; //在所有的4种情况下,都会把任务控制块中的OSTCBFlagNode 937 //指针重新赋值为NULL。因为任务得到了预期的事件标志,则OSFlagPend() 938 //函数也将退出,建立OS_FLAG_NODE数据结构也将不复存在。 939 #endif 940 } 941 #endif 942