1 /* 2 ********************************************************************************************************* 3 * uC/OS-II实时控制内核 4 * 消息邮箱管理 5 * 文 件 : OS_MBOX.C 消息邮件管理代码 6 * 作 者 : Jean J. Labrosse 7 * 中文注解: 钟常慰 zhongcw @ 126.com 整理:lin-credible 译注版本:1.0 请尊重原版内容 8 ********************************************************************************************************* 9 */ 10 11 #ifndef OS_MASTER_FILE //是否已经定义OS_MASTER_FILE 12 #include "includes.h" //包含"includes.h"文件 13 #endif //结束定义 14 15 #if OS_MBOX_EN > 0 //条件编译允许(1)产生消息邮箱相关代码 16 /* 17 ********************************************************************************************************* 18 * 查看指定的消息邮箱是否有需要的消息(ACCEPT MESSAGE FROM MAILBOX) 19 * 20 * 描述: OSMboxAccept()函数查看指定的消息邮箱是否有需要的消息。不同于OSMboxPend()函数,如果没有需要的消息, 21 * OSMboxAccept()函数并不挂起任务。如果消息已经到达,该消息被传递到用户任务并且从消息邮箱中清除。通 22 * 常中断调用该函数,因为中断不允许挂起等待消息。 23 * 24 * 意见: pevent 是指向需要查看的消息邮箱的指针。当建立消息邮箱时,该指针返回到用户程序。 25 * (参考OSMboxCreate()函数)。 26 * 27 * 返回: 如果消息已经到达,返回指向该消息的指针;如果消息邮箱没有消息,返回空指针。 28 * 29 * 注意: 必须先建立消息邮箱,然后使用。 30 ********************************************************************************************************* 31 */ 32 33 #if OS_MBOX_ACCEPT_EN > 0 //允许(1)生成 OSMboxAccept()代码 34 void *OSMboxAccept (OS_EVENT *pevent) //查看消息邮箱(消息邮箱指针) 35 { 36 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 37 OS_CPU_SR cpu_sr; 38 #endif 39 void *msg; //定义消息邮箱内容的指针 40 41 42 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 43 if (pevent == (OS_EVENT *)0) { //当消息邮箱指针为NULL时,返回0,空指针 44 return ((void *)0); 45 } 46 if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { //当事件类型≠消息邮箱类型 47 return ((void *)0); //返回空指针 48 } 49 #endif 50 OS_ENTER_CRITICAL(); //关闭中断 51 msg = pevent->OSEventPtr; //取消息邮箱中的内容 52 pevent->OSEventPtr = (void *)0; //将消息邮箱的内容清0 53 OS_EXIT_CRITICAL(); //打开中断 54 return (msg); //返回消息,如果为空,说明没有消息;不为空,说明有内容 55 } 56 #endif 57 /*$PAGE*/ 58 /* 59 ********************************************************************************************************* 60 * 建立并初始化一个消息邮箱(CREATE A MESSAGE MAILBOX) 61 * 62 * 描述: 建立并初始化一个消息邮箱。消息邮箱允许任务或中断向其他一个或几个任务发送消息。 63 * 64 * 参数: msg 参数用来初始化建立的消息邮箱。如果该指针不为空,建立的消息邮箱将含有消息。 65 * 66 * 返回: 指向分配给所建立的消息邮箱的事件控制块的指针。如果没有可用的事件控制块,返回空指针。 67 * 68 * 注意: 必须先建立消息邮箱,然后使用。 69 ********************************************************************************************************* 70 */ 71 72 OS_EVENT *OSMboxCreate (void *msg) //建立并初始化一个消息邮箱(msg 参数不为空含内容) 73 { 74 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 75 OS_CPU_SR cpu_sr; 76 #endif 77 OS_EVENT *pevent; //定义一个指向事件控制块的指针 78 79 80 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行 81 return ((OS_EVENT *)0); //返回0 82 } 83 OS_ENTER_CRITICAL(); //关闭中断 84 pevent = OSEventFreeList; //pevent=空余事件管理列表 85 if (OSEventFreeList != (OS_EVENT *)0) { //如果有空余事件管理块 86 OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; 87 } //空余事件控制链表指向下一个空余事件控制块 88 OS_EXIT_CRITICAL(); //打开中断 89 if (pevent != (OS_EVENT *)0) { //如果有空余的事件控制块可用 90 pevent->OSEventType = OS_EVENT_TYPE_MBOX; //则这个类型=消息邮箱类形 91 pevent->OSEventPtr = msg; //将初始值存入事件管理块ECB中 92 OS_EventWaitListInit(pevent); //初始化一个事件控制块 93 } 94 return (pevent); //返回该详细邮箱(事件)的指针,即邮箱句柄 95 } 96 /*$PAGE*/ 97 /* 98 ********************************************************************************************************* 99 * 删除消息邮箱 (DELETE A MAIBOX) 100 * 101 * 描述: 删除消息邮箱。因为多任务可能会试图继续使用已经删除了的邮箱,故调用本函数有风险。使用本函数 102 * 须特别小心。一般的说,删除邮箱之前,应该首先删除与本邮箱有关的任务。 103 * 104 * 描述: pevent 指向邮箱得指针.该指针是在邮箱建立时,返回给用户应用程序的指针.(参考OSMboxCreate()) 105 * 106 * opt 该选项定义邮箱的删除条件: 107 * opt == OS_DEL_NO_PEND 可以选择只能在已经没有任何任务在等待该邮箱的消息时,才能删除邮箱; 108 * opt == OS_DEL_ALWAYS 不管有没有任务在等待邮箱的消息,立即删除邮箱。 109 * -->第2种情况下,所有等待邮箱消息的任务都立即进入就绪态。 110 * 111 * err 指向错误代码的指针,返回出错代码可以是以下几种之一: 112 * OS_NO_ERR 调用成功,邮箱已经删除; 113 * OS_ERR_DEL_ISR 试图在中断服务子程序中删除邮箱; 114 * OS_ERR_INVALID_OPT 无效的opt参数,用户没有将opt定义为上述2种情况之一; 115 * OS_ERR_TASK_WAITING 一个或更多的任务在等待邮箱的消息; 116 * OS_ERR_EVENT_TYPE pevent不是指向邮箱的指针; 117 * OS_ERR_PEVENT_NULL 已经没有OS_EVENT数据结构可以使用。 118 * 119 * 返回: pevent 返回空指针NULL,表示邮箱已被删除,返回pevent,表示邮箱没有删除,在这种情况下,应该进一步 120 * 查看出错代码,找到出错原因。 121 * 122 * 注意: 1) 使用这个函数调用时,须特别小心。因为其他任务可能还要用这个邮箱。 123 * 2) 当挂起的任务进入就绪态时,中断是关闭的,这就意味着中断延迟时间与在等待邮箱的消息的任务数有关。 124 * 3) 调用OSMboxAccept()函数也不可能知道邮箱是否已经被删除了。 125 ********************************************************************************************************* 126 */ 127 128 #if OS_MBOX_DEL_EN > 0 //允许(1)生成 OSMboxDel()代码 129 //删除消息邮箱(消息邮箱指针、删除条件、出错代码指针) 130 OS_EVENT *OSMboxDel (OS_EVENT *pevent, INT8U opt, INT8U *err) 131 { 132 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 133 OS_CPU_SR cpu_sr; 134 #endif 135 BOOLEAN tasks_waiting; //定义布尔量,任务等待条件 136 137 138 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行 139 *err = OS_ERR_DEL_ISR; //错误等于(试图在中断程序中删除一个信号量事件) 140 return (pevent); //返回消息邮箱指针 141 } 142 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 143 if (pevent == (OS_EVENT *)0) { //当消息邮箱指针为NULL,即0(空) 144 *err = OS_ERR_PEVENT_NULL; //错误等于(已经没有可用的OS_EVENT数据结构了) 145 return (pevent); //返回消息邮箱指针 146 } 147 if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { //当事件类型不否是消息邮箱类型 148 *err = OS_ERR_EVENT_TYPE; //pevent指针不是指向消息邮箱 149 return (pevent); //返回消息邮箱指针 150 } 151 #endif 152 OS_ENTER_CRITICAL(); //关闭中断 153 if (pevent->OSEventGrp != 0x00) { //事件等待标志,索引值≠0,有任务在等待 154 tasks_waiting = TRUE; //有任务在等待=1(TRUE真) 155 } else { 156 tasks_waiting = FALSE; //否则,没有任务在等待=0,(FALSE假) 157 } 158 switch (opt) { //条件选择 159 case OS_DEL_NO_PEND: //1)没有任务在等待该消息邮箱 160 if (tasks_waiting == FALSE) { //如果没有事件在等待 161 pevent->OSEventType = OS_EVENT_TYPE_UNUSED; //事件类型=空闲 162 pevent->OSEventPtr = OSEventFreeList; //信号量对应的指针=空余块链接表 163 OSEventFreeList = pevent; //空余块链接表=当前事件指针 164 OS_EXIT_CRITICAL(); //关闭中断 165 *err = OS_NO_ERR; //错误等于(成功删除) 166 return ((OS_EVENT *)0); //返回0 167 } else { //否则,有任务在等待 168 OS_EXIT_CRITICAL(); //打开中断 169 *err = OS_ERR_TASK_WAITING; //错误等于(有一个或一个以上的任务在等待消息邮箱) 170 return (pevent); //返回消息邮箱指针 171 } 172 173 case OS_DEL_ALWAYS: //2)多任务等待,尽管有任务在等待,还是要删除 174 while (pevent->OSEventGrp != 0x00) { //等待标志≠0,还是要删除 175 //OS_EventTaskRdy()函数将最高级优先级任务从等待列表中删除 176 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX); //使一个任务进入就绪态 177 } 178 pevent->OSEventType = OS_EVENT_TYPE_UNUSED; //事件类型=空闲 179 pevent->OSEventPtr = OSEventFreeList; //消息邮箱对应的指针=空余块链接表 180 OSEventFreeList = pevent; //空余块链接表=当前事件指针 181 OS_EXIT_CRITICAL(); //关闭中断 182 if (tasks_waiting == TRUE) { //当任务等待=1,真 183 OS_Sched(); //任务调度,最高优先级进入运行状态 184 } 185 *err = OS_NO_ERR; //错误等于(成功删除) 186 return ((OS_EVENT *)0); //返回0 187 188 default: // 3)当以上两种情况都不是 189 OS_EXIT_CRITICAL(); //关闭中断 190 *err = OS_ERR_INVALID_OPT; //错误等于(没有将opt参数定义为2种合法的参数之一) 191 return (pevent); //返回信号量指针 192 } 193 } 194 #endif 195 196 /*$PAGE*/ 197 /* 198 ********************************************************************************************************* 199 * 任务等待消息(PEND ON MAILBOX FOR A MESSAGE) 200 * 201 * 描述: 用于任务等待消息。消息通过中断或另外的任务发送给需要的任务。 202 * 203 * 参数: pevent 是指向即将接受消息的消息邮箱的指针。该指针的值在建立该消息邮箱时可以得到。 204 * 205 * timeout 允许一个任务在经过了指定数目的时钟节拍后还没有得到需要的消息时恢复运行。如果该值为零表 206 * 示任务将持续的等待消息。最大的等待时间为65,535个时钟节拍。这个时间长度并不是非常严格的, 207 * 可能存在一个时钟节拍的误差,因为只有在一个时钟节拍结束后才会减少定义的等待超时时钟节拍。 208 * 209 * err 是指向包含错误码的变量的指针。OSMboxPend()函数返回的错误码可能为下述几种: 210 * 211 * OS_NO_ERR 消息被正确的接受; 212 * OS_TIMEOUT 消息没有在指定的周期数内送到; 213 * OS_ERR_EVENT_TYPE pevent 不是指向消息邮箱的指针; 214 * OS_ERR_PEND_ISR 从中断调用该函数。虽然规定了不允许从中断调用该函数,但uC/OS-ii仍 215 * 然包含了检测这种情况的功能; 216 * OS_ERR_PEVENT_NULL 'pevent'是空指针。 217 * 218 * 返回: 返回接受的消息并将 *err置为OS_NO_ERR。如果没有在指定数目的时钟节拍内接受到需要的消息, 219 * OSMboxPend()函数返回空指针并且将 *err设置为OS_TIMEOUT。 220 * 221 * 注意: 必须先建立消息邮箱,然后使用。 222 * 不允许从中断调用该函数。 223 ********************************************************************************************************* 224 */ 225 //等待一个消息邮箱函数(消息邮箱指针、允许等待的时钟节拍、代码错误指针) 226 void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) 227 { 228 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 229 OS_CPU_SR cpu_sr; 230 #endif 231 void *msg; //定义消息邮箱内容的指针 232 233 234 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行 235 *err = OS_ERR_PEND_ISR; //错误等于(试图在中断程序中等待一个消息邮箱事件) 236 return ((void *)0); //返回 237 } 238 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 239 if (pevent == (OS_EVENT *)0) { //当邮箱指针为NULL,即0(空) 240 *err = OS_ERR_PEVENT_NULL; //pevent是空指针 241 return ((void *)0); //返回 242 } 243 if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { //当事件类型不否是消息邮箱类型 244 *err = OS_ERR_EVENT_TYPE; //pevent指针不是指向消息邮箱 245 return ((void *)0); //返回 246 } 247 #endif 248 OS_ENTER_CRITICAL(); //关闭中断 249 msg = pevent->OSEventPtr; //试取消息邮箱内容 250 if (msg != (void *)0) { //检查消息邮箱是否为空 251 pevent->OSEventPtr = (void *)0; //将0存入消息邮箱中 252 OS_EXIT_CRITICAL(); //打开中断 253 *err = OS_NO_ERR; //返回成功调用,取出消息 254 return (msg); //返回接收消息 255 } //如果消息邮箱为空,则进入等待中 256 OSTCBCur->OSTCBStat |= OS_STAT_MBOX; //将任务状态置1,进入睡眠状态,只能通过消息邮箱唤醒 257 OSTCBCur->OSTCBDly = timeout; //最长等待时间=timeout,递减式 258 OS_EventTaskWait(pevent); //使任务进入等待时间唤醒状态 259 OS_EXIT_CRITICAL(); //打开中断 260 OS_Sched(); //进入调度任务,使就绪态优先级最高任务运行 261 OS_ENTER_CRITICAL(); //关闭中断 262 msg = OSTCBCur->OSTCBMsg; //接收消息=指向任务消息的指针 263 if (msg != (void *)0) { //接收消息邮箱是否为空 264 OSTCBCur->OSTCBMsg = (void *)0; //传递给消息的指针=空 265 OSTCBCur->OSTCBStat = OS_STAT_RDY; //表示任务处于就绪状态 266 OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; //指向事件控制块的指针=0 267 OS_EXIT_CRITICAL(); //打开中断 268 *err = OS_NO_ERR; //成功等待该消息邮箱 269 return (msg); //返回接收消息 270 } 271 OS_EventTO(pevent); //如果没有获得消息,由于等待超时而返回 272 OS_EXIT_CRITICAL(); //打开中断 273 *err = OS_TIMEOUT; //消息没有在指定的时间送到 274 return ((void *)0); //返回0 275 } 276 /*$PAGE*/ 277 /* 278 ********************************************************************************************************* 279 * 通过消息邮箱向任务发送消息(POST MESSAGE TO A MAILBOX) 280 * 281 * 描述: 通过消息邮箱向任务发送消息。消息是一个指针长度的变量,在不同的程序中消息的使用也可能不同。如果 282 * 消息邮箱中已经存在消息,返回错误码说明消息邮箱已满。OSMboxPost()函数立即返回调用者,消息也没 283 * 有能够发到消息邮箱。如果有任何任务在等待消息邮箱的消息,最高优先级的任务将得到这个消息。如果等 284 * 待消息的任务优先级比发送消息的任务优先级高,那么高优先级的任务将得到消息而恢复执行,也就是说, 285 * 发生了一次任务切换。 286 * 287 * 参数: pevent 是指向即将接受消息的消息邮箱的指针。该指针的值在建立该消息邮箱时可以得到。 288 * 参考OSMboxCreate()函数 289 * 290 * msg 是即将实际发送给任务的消息。消息是一个指针长度的变量,在不同的程序中消息的使用也可能不 291 * 同。不允许传递一个空指针,因为这意味着消息邮箱为空。 292 * 293 * 返回: OS_NO_ERR 消息成功的放到消息邮箱中; 294 * OS_MBOX_FULL 消息邮箱已经包含了其他消息,不空; 295 * OS_ERR_EVENT_TYPE 'pevent'不是指向消息邮箱的指针; 296 * OS_ERR_PEVENT_NULL 'pevent'是空指针。 297 * OS_ERR_POST_NULL_PTR 用户试图发出空指针。根据规则,在这里不支持空指针。 298 * 299 * 注意: 必须先建立消息邮箱,然后使用。 300 * 不允许传递一个空指针,因为这意味着消息邮箱为空。 301 ********************************************************************************************************* 302 */ 303 304 #if OS_MBOX_POST_EN > 0 //允许(1)生成 OSMboxPost()代码 305 INT8U OSMboxPost (OS_EVENT *pevent, void *msg) //发送消息函数(消息邮箱指针、即将实际发送给任务的消息) 306 { 钟常慰 307 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 308 OS_CPU_SR cpu_sr; 309 #endif 310 311 312 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 313 if (pevent == (OS_EVENT *)0) { //当邮箱指针为NULL,即0(空) 314 return (OS_ERR_PEVENT_NULL); //返回(pevent是空指针) 315 } 316 if (msg == (void *)0) { //检查消息是否为空 317 return (OS_ERR_POST_NULL_PTR); //返回(用户试图发出空指针)不支持空指针 318 } 319 if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { //事件发送标志是否是邮箱标志 320 return (OS_ERR_EVENT_TYPE); //'pevent'不是指向消息邮箱的指针 321 } 322 #endif 323 OS_ENTER_CRITICAL(); //关闭中断 324 if (pevent->OSEventGrp != 0x00) { //是否有任务在等待该邮箱,索引值≠0 325 //OS_EventTaskRdy()函数将最高级优先级任务从等待列表中删除 326 OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX); 327 OS_EXIT_CRITICAL(); //关闭中断 328 OS_Sched(); //如果该任务不是最高优先级,进入(任务调度) 329 return (OS_NO_ERR); //消息成功的放到消息邮箱中; 330 } 331 if (pevent->OSEventPtr != (void *)0) { //事件邮箱指针=空 332 OS_EXIT_CRITICAL(); //打开中断 333 return (OS_MBOX_FULL); //消息邮箱中已经包含了其它的消息(邮箱已满) 334 } 335 pevent->OSEventPtr = msg; //指向消息的指针保存到邮箱中 336 OS_EXIT_CRITICAL(); //打开中断 337 return (OS_NO_ERR); //消息成功的放到消息邮箱中 338 } 339 #endif 340 341 /*$PAGE*/ 342 /* 343 ********************************************************************************************************* 344 * 通过邮箱向(多)任务发送消息 (POST MESSAGE TO A MAILBOX) 345 * 346 * 描述: OSMboxPostOpt()与OSMboxPost()相同,只是允许用户程序发消息给多个任务。也就是允许将消息广播给 347 * 所有的等待邮箱消息的任务。OSMboxPostOpt()实际上取代OSMboxPost(),因为它可仿真OSMboxPost(). 348 * 349 * 通过邮箱向任务发送消息。消息是一个指针长度的变量,在不同的程序中消息的使用也可能不同。如果 350 * 消息邮箱中已经存在消息,返回错误码说明消息邮箱已满。OSMboxPostOpt()函数立即返回调用者,消息 351 * 也没有能够发到消息邮箱。如果有任何任务在等待消息邮箱的消息,那么OSMboxPostOpt()允许选择2种 352 * 情况之一:1、定义消息只发送给等待邮箱消息得任务中优先级最高得任务,2、让所有等待邮箱消息得, 353 * 任务都得到消息无论在那种条件下,如果得到消息的任务优先级比发送消息的任务优先级高,那么得到 354 * 消息的最高优先级的任务将恢复执行,发消息的任务将被挂起。也就是发生一次任务切换。 355 * 356 * 参数: pevent 是指向即将发送消息的消息邮箱的指针。该指针的值在建立该消息邮箱时可以得到。 357 * 参考OSMboxCreate()函数. 358 * 359 * msg 是即将实际发送给任务的消息。消息是一个指针长度的变量,在不同的程序中消息的使用也可能 360 * 不同。不允许传递一个空指针,因为这意味着消息邮箱为空。 361 * 362 * opt 该选项定义邮箱的发送条件: 363 * OS_POST_OPT_NONE 定义消息只发送给等待邮箱消息得任务中优先级最高得任务; 364 * OS_POST_OPT_BROADCAST 让所有等待邮箱消息得任务都得到消息。 365 * 366 * 返回: OS_NO_ERR 消息成功的放到消息邮箱中; 367 * OS_MBOX_FULL 消息邮箱已经包含了其他消息,已满; 368 * OS_ERR_EVENT_TYPE 'pevent'不是指向消息邮箱的指针; 369 * S_ERR_PEVENT_NULL 'pevent'是空指针 370 * OS_ERR_POST_NULL_PTR 用户试图发出空指针。根据规则,在这里不支持空指针。 371 * 372 * 警告: 1) 必须先建立消息邮箱,然后再使用; 373 * 2) 不允许向邮箱发送空指针,因为这意味着消息邮箱为空; 374 * 3) 若想使用本函数,又希望压缩代码长度,则可以将OSMboxPost()函数得开关量关掉; 375 * 因为OSMboxPostOpt()可以仿真OSMboxPost(). 376 * 4) OSMboxPostOpt()在广播方式下,即已将opt置为OS_POST_OPT_BROADCAST,函数的执行时间取决与等待 377 * 邮箱消息的任务的数目。 378 ********************************************************************************************************* 379 */ 380 381 #if OS_MBOX_POST_OPT_EN > 0 //允许(1)生成 OSMboxPost()代码 382 INT8U OSMboxPostOpt (OS_EVENT *pevent, void *msg, INT8U opt) 383 { //向邮箱发送一则消息(邮箱指针、消息、条件) 384 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 385 OS_CPU_SR cpu_sr; 386 #endif 387 388 389 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 390 if (pevent == (OS_EVENT *)0) { //当邮箱指针为NULL,即0(空) 391 return (OS_ERR_PEVENT_NULL); //返回(pevent是空指针) 392 } 393 if (msg == (void *)0) { //检查消息是否为空指针 394 return (OS_ERR_POST_NULL_PTR); //返回(用户试图发出空指针),不支持空指针 395 } 396 if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { //事件发送标志是否是邮箱标志 397 return (OS_ERR_EVENT_TYPE); //'pevent'不是指向消息邮箱的指针 398 } 399 #endif 400 OS_ENTER_CRITICAL(); //关闭中断 401 if (pevent->OSEventGrp != 0x00) { //是否有任务在等待该邮箱,索引值≠0 402 //如果opt必须为OS_POST_OPT_BROADCAST,所有的任务都得到该消息 403 if ((opt & OS_POST_OPT_BROADCAST) != 0x00) { //如果opt必须为OS_POST_OPT_BROADCAST 404 while (pevent->OSEventGrp != 0x00) { //如果是,所有的任务都得到该消息 // OS_EventTaskRdy()函数将最高级优先级任务从等待列表中删除 405 OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX); 406 } 407 } else { //如果没有请求广播,那么只有最高任务进入就绪态,准备运行 408 // OS_EventTaskRdy()函数将最高级优先级任务从等待列表中删除 409 OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX); 410 } 411 OS_EXIT_CRITICAL(); //打开中断 412 OS_Sched(); //如果该任务不是最高优先级,进入(任务调度) 413 return (OS_NO_ERR); //消息成功的放到消息邮箱中 414 } 415 if (pevent->OSEventPtr != (void *)0) { //是否有任务在等待该邮箱,索引值≠0 416 OS_EXIT_CRITICAL(); //打开中断 417 return (OS_MBOX_FULL); //消息邮箱已经包含了其他消息,已满 418 } 419 pevent->OSEventPtr = msg; //将消息的指针保存到邮箱中 420 OS_EXIT_CRITICAL(); //打开中断 421 return (OS_NO_ERR); //消息成功的放到消息邮箱中 422 } 423 #endif 424 425 /*$PAGE*/ 426 /* 427 ********************************************************************************************************* 428 * 取得消息邮箱的信息(QUERY A MESSAGE MAILBOX) 429 * 430 * 描述: 用来取得消息邮箱的信息。用户程序必须分配一个OS_MBOX_DATA的数据结构,该结构用来从消息邮箱的事件 431 * 控制块接受数据。通过调用OSMboxQuery()函数可以知道任务是否在等待消息以及有多少个任务在等待消息, 432 * 还可以检查消息邮箱现在的消息。 433 * 434 * 参数: pevent 是指向即将接受消息的消息邮箱的指针。该指针的值在建立该消息邮箱时可以得到。 435 * 436 * pdata 是指向OS_MBOX_DATA数据结构的指针,该数据结构包含下述成员: 437 * Void *OSMsg; /* 消息邮箱中消息的复制 */ 438 * INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* 消息邮箱等待队列的复制 */ 439 * INT8U OSEventGrp; 440 * 441 * 返回: OS_NO_ERR 调用成功 442 * OS_ERR_EVENT_TYPE 'pevent'不是指向消息邮箱的指针。 443 * OS_ERR_PEVENT_NULL 'pevent'是空指针。 444 *注意: 必须先建立消息邮箱,然后使用 445 ********************************************************************************************************* 446 */ 447 448 #if OS_MBOX_QUERY_EN > 0 //允许(1)生成 OSMboxPost()代码 449 INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata) 450 { //查询一个邮箱的当前状态(信号量指针、状态数据结构指针) 451 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 452 OS_CPU_SR cpu_sr; //返回(pevent是空指针) 453 #endif 454 INT8U *psrc; //定义8位pevent->OSEventTbl[0]的地址指针 455 INT8U *pdest; //定义8位pdata->OSEventTbl[0]的地址指针 456 457 458 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内 459 if (pevent == (OS_EVENT *)0) { //当邮箱指针为NULL,即0(空) 460 return (OS_ERR_PEVENT_NULL); //返回(pevent是空指针) 461 } 462 if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { //当事件类型不是邮箱类型 463 return (OS_ERR_EVENT_TYPE); //'pevent'不是指向消息邮箱的指针 464 } 465 #endif 466 OS_ENTER_CRITICAL(); //关闭中断 467 //将事件(邮箱)结构中的等待任务列表复制到pdata数据结构中 468 pdata->OSEventGrp = pevent->OSEventGrp; //等待事件的任务组中的内容传送到状态数据结构中 469 psrc = &pevent->OSEventTbl[0]; //保存pevent->OSEventTbl[0]对应的地址 470 pdest = &pdata->OSEventTbl[0]; //保存pdata->OSEventTbl[0]对应的地址 471 472 #if OS_EVENT_TBL_SIZE > 0 //当事件就绪对应表中的对应值>0时 473 *pdest++ = *psrc++; //地址指针下移一个类型地址,获取消息邮箱的值 474 #endif 475 476 #if OS_EVENT_TBL_SIZE > 1 //事件就绪对应表中的对应值>1时 477 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取消息邮箱的值 478 #endif 479 480 #if OS_EVENT_TBL_SIZE > 2 //事件就绪对应表中的对应值>1时 481 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取消息邮箱的值 482 #endif 483 484 #if OS_EVENT_TBL_SIZE > 3 //事件就绪对应表中的对应值>1时 485 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取消息邮箱的值 486 #endif 487 488 #if OS_EVENT_TBL_SIZE > 4 //事件就绪对应表中的对应值>1时 489 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取消息邮箱的值 490 #endif 491 492 #if OS_EVENT_TBL_SIZE > 5 //事件就绪对应表中的对应值>1时 493 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取消息邮箱的值 494 #endif 495 496 #if OS_EVENT_TBL_SIZE > 6 //事件就绪对应表中的对应值>1时 497 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取消息邮箱的值 498 #endif 499 500 #if OS_EVENT_TBL_SIZE > 7 //事件就绪对应表中的对应值>7时 501 *pdest = *psrc; //获取最后地址的信号量的值 502 #endif 503 pdata->OSMsg = pevent->OSEventPtr; //将邮箱中的当前消息从事件数据结构复制到OS_MBOX_DATA数据结构中 504 OS_EXIT_CRITICAL(); //打开中断 505 return (OS_NO_ERR); //返回成功运行 506 } 507 #endif // OS_MBOX_QUERY_EN 函数结束 508 #endif // OS_MBOX_EN文件结束 509