os_q.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * MESSAGE QUEUE MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2009, Micrium, Weston, FL
  8. * All Rights Reserved
  9. *
  10. * File : OS_Q.C
  11. * By : Jean J. Labrosse
  12. * Version : V2.91
  13. *
  14. * LICENSING TERMS:
  15. * ---------------
  16. * uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
  17. * If you plan on using uC/OS-II in a commercial product you need to contact Micriµm to properly license
  18. * its use in your product. We provide ALL the source code for your convenience and to help you experience
  19. * uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
  20. * licensing fee.
  21. *********************************************************************************************************
  22. */
  23. #ifndef OS_MASTER_FILE
  24. #include <ucos_ii.h>
  25. #endif
  26. #if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
  27. /*
  28. *********************************************************************************************************
  29. * ACCEPT MESSAGE FROM QUEUE
  30. *
  31. * Description: This function checks the queue to see if a message is available. Unlike OSQPend(),
  32. * OSQAccept() does not suspend the calling task if a message is not available.
  33. *
  34. * Arguments : pevent is a pointer to the event control block
  35. *
  36. * perr is a pointer to where an error message will be deposited. Possible error
  37. * messages are:
  38. *
  39. * OS_ERR_NONE The call was successful and your task received a
  40. * message.
  41. * OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
  42. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  43. * OS_ERR_Q_EMPTY The queue did not contain any messages
  44. *
  45. * Returns : != (void *)0 is the message in the queue if one is available. The message is removed
  46. * from the so the next time OSQAccept() is called, the queue will contain
  47. * one less entry.
  48. * == (void *)0 if you received a NULL pointer message
  49. * if the queue is empty or,
  50. * if 'pevent' is a NULL pointer or,
  51. * if you passed an invalid event type
  52. *
  53. * Note(s) : As of V2.60, you can now pass NULL pointers through queues. Because of this, the argument
  54. * 'perr' has been added to the API to tell you about the outcome of the call.
  55. *********************************************************************************************************
  56. */
  57. #if OS_Q_ACCEPT_EN > 0u
  58. void *OSQAccept (OS_EVENT *pevent,
  59. INT8U *perr)
  60. {
  61. void *pmsg;
  62. OS_Q *pq;
  63. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  64. OS_CPU_SR cpu_sr = 0u;
  65. #endif
  66. #ifdef OS_SAFETY_CRITICAL
  67. if (perr == (INT8U *)0) {
  68. OS_SAFETY_CRITICAL_EXCEPTION();
  69. }
  70. #endif
  71. #if OS_ARG_CHK_EN > 0u
  72. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  73. *perr = OS_ERR_PEVENT_NULL;
  74. return ((void *)0);
  75. }
  76. #endif
  77. if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
  78. *perr = OS_ERR_EVENT_TYPE;
  79. return ((void *)0);
  80. }
  81. OS_ENTER_CRITICAL();
  82. pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
  83. if (pq->OSQEntries > 0u) { /* See if any messages in the queue */
  84. pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
  85. pq->OSQEntries--; /* Update the number of entries in the queue */
  86. if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */
  87. pq->OSQOut = pq->OSQStart;
  88. }
  89. *perr = OS_ERR_NONE;
  90. } else {
  91. *perr = OS_ERR_Q_EMPTY;
  92. pmsg = (void *)0; /* Queue is empty */
  93. }
  94. OS_EXIT_CRITICAL();
  95. return (pmsg); /* Return message received (or NULL) */
  96. }
  97. #endif
  98. /*$PAGE*/
  99. /*
  100. *********************************************************************************************************
  101. * CREATE A MESSAGE QUEUE
  102. *
  103. * Description: This function creates a message queue if free event control blocks are available.
  104. *
  105. * Arguments : start is a pointer to the base address of the message queue storage area. The
  106. * storage area MUST be declared as an array of pointers to 'void' as follows
  107. *
  108. * void *MessageStorage[size]
  109. *
  110. * size is the number of elements in the storage area
  111. *
  112. * Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the
  113. * created queue
  114. * == (OS_EVENT *)0 if no event control blocks were available or an error was detected
  115. *********************************************************************************************************
  116. */
  117. OS_EVENT *OSQCreate (void **start,
  118. INT16U size)
  119. {
  120. OS_EVENT *pevent;
  121. OS_Q *pq;
  122. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  123. OS_CPU_SR cpu_sr = 0u;
  124. #endif
  125. #ifdef OS_SAFETY_CRITICAL_IEC61508
  126. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  127. OS_SAFETY_CRITICAL_EXCEPTION();
  128. }
  129. #endif
  130. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  131. return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
  132. }
  133. OS_ENTER_CRITICAL();
  134. pevent = OSEventFreeList; /* Get next free event control block */
  135. if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
  136. OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  137. }
  138. OS_EXIT_CRITICAL();
  139. if (pevent != (OS_EVENT *)0) { /* See if we have an event control block */
  140. OS_ENTER_CRITICAL();
  141. pq = OSQFreeList; /* Get a free queue control block */
  142. if (pq != (OS_Q *)0) { /* Were we able to get a queue control block ? */
  143. OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
  144. OS_EXIT_CRITICAL();
  145. pq->OSQStart = start; /* Initialize the queue */
  146. pq->OSQEnd = &start[size];
  147. pq->OSQIn = start;
  148. pq->OSQOut = start;
  149. pq->OSQSize = size;
  150. pq->OSQEntries = 0u;
  151. pevent->OSEventType = OS_EVENT_TYPE_Q;
  152. pevent->OSEventCnt = 0u;
  153. pevent->OSEventPtr = pq;
  154. #if OS_EVENT_NAME_EN > 0u
  155. pevent->OSEventName = (INT8U *)(void *)"?";
  156. #endif
  157. OS_EventWaitListInit(pevent); /* Initalize the wait list */
  158. } else {
  159. pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */
  160. OSEventFreeList = pevent;
  161. OS_EXIT_CRITICAL();
  162. pevent = (OS_EVENT *)0;
  163. }
  164. }
  165. return (pevent);
  166. }
  167. /*$PAGE*/
  168. /*
  169. *********************************************************************************************************
  170. * DELETE A MESSAGE QUEUE
  171. *
  172. * Description: This function deletes a message queue and readies all tasks pending on the queue.
  173. *
  174. * Arguments : pevent is a pointer to the event control block associated with the desired
  175. * queue.
  176. *
  177. * opt determines delete options as follows:
  178. * opt == OS_DEL_NO_PEND Delete the queue ONLY if no task pending
  179. * opt == OS_DEL_ALWAYS Deletes the queue even if tasks are waiting.
  180. * In this case, all the tasks pending will be readied.
  181. *
  182. * perr is a pointer to an error code that can contain one of the following values:
  183. * OS_ERR_NONE The call was successful and the queue was deleted
  184. * OS_ERR_DEL_ISR If you tried to delete the queue from an ISR
  185. * OS_ERR_INVALID_OPT An invalid option was specified
  186. * OS_ERR_TASK_WAITING One or more tasks were waiting on the queue
  187. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue
  188. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  189. *
  190. * Returns : pevent upon error
  191. * (OS_EVENT *)0 if the queue was successfully deleted.
  192. *
  193. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  194. * the queue MUST check the return code of OSQPend().
  195. * 2) OSQAccept() callers will not know that the intended queue has been deleted unless
  196. * they check 'pevent' to see that it's a NULL pointer.
  197. * 3) This call can potentially disable interrupts for a long time. The interrupt disable
  198. * time is directly proportional to the number of tasks waiting on the queue.
  199. * 4) Because ALL tasks pending on the queue will be readied, you MUST be careful in
  200. * applications where the queue is used for mutual exclusion because the resource(s)
  201. * will no longer be guarded by the queue.
  202. * 5) If the storage for the message queue was allocated dynamically (i.e. using a malloc()
  203. * type call) then your application MUST release the memory storage by call the counterpart
  204. * call of the dynamic allocation scheme used. If the queue storage was created statically
  205. * then, the storage can be reused.
  206. *********************************************************************************************************
  207. */
  208. #if OS_Q_DEL_EN > 0u
  209. OS_EVENT *OSQDel (OS_EVENT *pevent,
  210. INT8U opt,
  211. INT8U *perr)
  212. {
  213. BOOLEAN tasks_waiting;
  214. OS_EVENT *pevent_return;
  215. OS_Q *pq;
  216. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  217. OS_CPU_SR cpu_sr = 0u;
  218. #endif
  219. #ifdef OS_SAFETY_CRITICAL
  220. if (perr == (INT8U *)0) {
  221. OS_SAFETY_CRITICAL_EXCEPTION();
  222. }
  223. #endif
  224. #if OS_ARG_CHK_EN > 0u
  225. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  226. *perr = OS_ERR_PEVENT_NULL;
  227. return (pevent);
  228. }
  229. #endif
  230. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  231. *perr = OS_ERR_EVENT_TYPE;
  232. return (pevent);
  233. }
  234. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  235. *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  236. return (pevent);
  237. }
  238. OS_ENTER_CRITICAL();
  239. if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on queue */
  240. tasks_waiting = OS_TRUE; /* Yes */
  241. } else {
  242. tasks_waiting = OS_FALSE; /* No */
  243. }
  244. switch (opt) {
  245. case OS_DEL_NO_PEND: /* Delete queue only if no task waiting */
  246. if (tasks_waiting == OS_FALSE) {
  247. #if OS_EVENT_NAME_EN > 0u
  248. pevent->OSEventName = (INT8U *)(void *)"?";
  249. #endif
  250. pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */
  251. pq->OSQPtr = OSQFreeList;
  252. OSQFreeList = pq;
  253. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  254. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  255. pevent->OSEventCnt = 0u;
  256. OSEventFreeList = pevent; /* Get next free event control block */
  257. OS_EXIT_CRITICAL();
  258. *perr = OS_ERR_NONE;
  259. pevent_return = (OS_EVENT *)0; /* Queue has been deleted */
  260. } else {
  261. OS_EXIT_CRITICAL();
  262. *perr = OS_ERR_TASK_WAITING;
  263. pevent_return = pevent;
  264. }
  265. break;
  266. case OS_DEL_ALWAYS: /* Always delete the queue */
  267. while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for queue */
  268. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_OK);
  269. }
  270. #if OS_EVENT_NAME_EN > 0u
  271. pevent->OSEventName = (INT8U *)(void *)"?";
  272. #endif
  273. pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */
  274. pq->OSQPtr = OSQFreeList;
  275. OSQFreeList = pq;
  276. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  277. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  278. pevent->OSEventCnt = 0u;
  279. OSEventFreeList = pevent; /* Get next free event control block */
  280. OS_EXIT_CRITICAL();
  281. if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
  282. OS_Sched(); /* Find highest priority task ready to run */
  283. }
  284. *perr = OS_ERR_NONE;
  285. pevent_return = (OS_EVENT *)0; /* Queue has been deleted */
  286. break;
  287. default:
  288. OS_EXIT_CRITICAL();
  289. *perr = OS_ERR_INVALID_OPT;
  290. pevent_return = pevent;
  291. break;
  292. }
  293. return (pevent_return);
  294. }
  295. #endif
  296. /*$PAGE*/
  297. /*
  298. *********************************************************************************************************
  299. * FLUSH QUEUE
  300. *
  301. * Description : This function is used to flush the contents of the message queue.
  302. *
  303. * Arguments : none
  304. *
  305. * Returns : OS_ERR_NONE upon success
  306. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue
  307. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  308. *
  309. * WARNING : You should use this function with great care because, when to flush the queue, you LOOSE
  310. * the references to what the queue entries are pointing to and thus, you could cause
  311. * 'memory leaks'. In other words, the data you are pointing to that's being referenced
  312. * by the queue entries should, most likely, need to be de-allocated (i.e. freed).
  313. *********************************************************************************************************
  314. */
  315. #if OS_Q_FLUSH_EN > 0u
  316. INT8U OSQFlush (OS_EVENT *pevent)
  317. {
  318. OS_Q *pq;
  319. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  320. OS_CPU_SR cpu_sr = 0u;
  321. #endif
  322. #if OS_ARG_CHK_EN > 0u
  323. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  324. return (OS_ERR_PEVENT_NULL);
  325. }
  326. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  327. return (OS_ERR_EVENT_TYPE);
  328. }
  329. #endif
  330. OS_ENTER_CRITICAL();
  331. pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue storage structure */
  332. pq->OSQIn = pq->OSQStart;
  333. pq->OSQOut = pq->OSQStart;
  334. pq->OSQEntries = 0u;
  335. OS_EXIT_CRITICAL();
  336. return (OS_ERR_NONE);
  337. }
  338. #endif
  339. /*$PAGE*/
  340. /*
  341. *********************************************************************************************************
  342. * PEND ON A QUEUE FOR A MESSAGE
  343. *
  344. * Description: This function waits for a message to be sent to a queue
  345. *
  346. * Arguments : pevent is a pointer to the event control block associated with the desired queue
  347. *
  348. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  349. * wait for a message to arrive at the queue up to the amount of time
  350. * specified by this argument. If you specify 0, however, your task will wait
  351. * forever at the specified queue or, until a message arrives.
  352. *
  353. * perr is a pointer to where an error message will be deposited. Possible error
  354. * messages are:
  355. *
  356. * OS_ERR_NONE The call was successful and your task received a
  357. * message.
  358. * OS_ERR_TIMEOUT A message was not received within the specified 'timeout'.
  359. * OS_ERR_PEND_ABORT The wait on the queue was aborted.
  360. * OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
  361. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  362. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  363. * would lead to a suspension.
  364. * OS_ERR_PEND_LOCKED If you called this function with the scheduler is locked
  365. *
  366. * Returns : != (void *)0 is a pointer to the message received
  367. * == (void *)0 if you received a NULL pointer message or,
  368. * if no message was received or,
  369. * if 'pevent' is a NULL pointer or,
  370. * if you didn't pass a pointer to a queue.
  371. *
  372. * Note(s) : As of V2.60, this function allows you to receive NULL pointer messages.
  373. *********************************************************************************************************
  374. */
  375. void *OSQPend (OS_EVENT *pevent,
  376. INT32U timeout,
  377. INT8U *perr)
  378. {
  379. void *pmsg;
  380. OS_Q *pq;
  381. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  382. OS_CPU_SR cpu_sr = 0u;
  383. #endif
  384. #ifdef OS_SAFETY_CRITICAL
  385. if (perr == (INT8U *)0) {
  386. OS_SAFETY_CRITICAL_EXCEPTION();
  387. }
  388. #endif
  389. #if OS_ARG_CHK_EN > 0u
  390. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  391. *perr = OS_ERR_PEVENT_NULL;
  392. return ((void *)0);
  393. }
  394. #endif
  395. if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
  396. *perr = OS_ERR_EVENT_TYPE;
  397. return ((void *)0);
  398. }
  399. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  400. *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  401. return ((void *)0);
  402. }
  403. if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */
  404. *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
  405. return ((void *)0);
  406. }
  407. OS_ENTER_CRITICAL();
  408. pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
  409. if (pq->OSQEntries > 0u) { /* See if any messages in the queue */
  410. pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
  411. pq->OSQEntries--; /* Update the number of entries in the queue */
  412. if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */
  413. pq->OSQOut = pq->OSQStart;
  414. }
  415. OS_EXIT_CRITICAL();
  416. *perr = OS_ERR_NONE;
  417. return (pmsg); /* Return message received */
  418. }
  419. OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */
  420. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
  421. OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */
  422. OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  423. OS_EXIT_CRITICAL();
  424. OS_Sched(); /* Find next highest priority task ready to run */
  425. OS_ENTER_CRITICAL();
  426. switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
  427. case OS_STAT_PEND_OK: /* Extract message from TCB (Put there by QPost) */
  428. pmsg = OSTCBCur->OSTCBMsg;
  429. *perr = OS_ERR_NONE;
  430. break;
  431. case OS_STAT_PEND_ABORT:
  432. pmsg = (void *)0;
  433. *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
  434. break;
  435. case OS_STAT_PEND_TO:
  436. default:
  437. OS_EventTaskRemove(OSTCBCur, pevent);
  438. pmsg = (void *)0;
  439. *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
  440. break;
  441. }
  442. OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
  443. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
  444. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
  445. #if (OS_EVENT_MULTI_EN > 0u)
  446. OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  447. #endif
  448. OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */
  449. OS_EXIT_CRITICAL();
  450. return (pmsg); /* Return received message */
  451. }
  452. /*$PAGE*/
  453. /*
  454. *********************************************************************************************************
  455. * ABORT WAITING ON A MESSAGE QUEUE
  456. *
  457. * Description: This function aborts & readies any tasks currently waiting on a queue. This function
  458. * should be used to fault-abort the wait on the queue, rather than to normally signal
  459. * the queue via OSQPost(), OSQPostFront() or OSQPostOpt().
  460. *
  461. * Arguments : pevent is a pointer to the event control block associated with the desired queue.
  462. *
  463. * opt determines the type of ABORT performed:
  464. * OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the
  465. * queue
  466. * OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the
  467. * queue
  468. *
  469. * perr is a pointer to where an error message will be deposited. Possible error
  470. * messages are:
  471. *
  472. * OS_ERR_NONE No tasks were waiting on the queue.
  473. * OS_ERR_PEND_ABORT At least one task waiting on the queue was readied
  474. * and informed of the aborted wait; check return value
  475. * for the number of tasks whose wait on the queue
  476. * was aborted.
  477. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
  478. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  479. *
  480. * Returns : == 0 if no tasks were waiting on the queue, or upon error.
  481. * > 0 if one or more tasks waiting on the queue are now readied and informed.
  482. *********************************************************************************************************
  483. */
  484. #if OS_Q_PEND_ABORT_EN > 0u
  485. INT8U OSQPendAbort (OS_EVENT *pevent,
  486. INT8U opt,
  487. INT8U *perr)
  488. {
  489. INT8U nbr_tasks;
  490. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  491. OS_CPU_SR cpu_sr = 0u;
  492. #endif
  493. #ifdef OS_SAFETY_CRITICAL
  494. if (perr == (INT8U *)0) {
  495. OS_SAFETY_CRITICAL_EXCEPTION();
  496. }
  497. #endif
  498. #if OS_ARG_CHK_EN > 0u
  499. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  500. *perr = OS_ERR_PEVENT_NULL;
  501. return (0u);
  502. }
  503. #endif
  504. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  505. *perr = OS_ERR_EVENT_TYPE;
  506. return (0u);
  507. }
  508. OS_ENTER_CRITICAL();
  509. if (pevent->OSEventGrp != 0u) { /* See if any task waiting on queue? */
  510. nbr_tasks = 0u;
  511. switch (opt) {
  512. case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */
  513. while (pevent->OSEventGrp != 0u) { /* Yes, ready ALL tasks waiting on queue */
  514. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
  515. nbr_tasks++;
  516. }
  517. break;
  518. case OS_PEND_OPT_NONE:
  519. default: /* No, ready HPT waiting on queue */
  520. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
  521. nbr_tasks++;
  522. break;
  523. }
  524. OS_EXIT_CRITICAL();
  525. OS_Sched(); /* Find HPT ready to run */
  526. *perr = OS_ERR_PEND_ABORT;
  527. return (nbr_tasks);
  528. }
  529. OS_EXIT_CRITICAL();
  530. *perr = OS_ERR_NONE;
  531. return (0u); /* No tasks waiting on queue */
  532. }
  533. #endif
  534. /*$PAGE*/
  535. /*
  536. *********************************************************************************************************
  537. * POST MESSAGE TO A QUEUE
  538. *
  539. * Description: This function sends a message to a queue
  540. *
  541. * Arguments : pevent is a pointer to the event control block associated with the desired queue
  542. *
  543. * pmsg is a pointer to the message to send.
  544. *
  545. * Returns : OS_ERR_NONE The call was successful and the message was sent
  546. * OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full.
  547. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
  548. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  549. *
  550. * Note(s) : As of V2.60, this function allows you to send NULL pointer messages.
  551. *********************************************************************************************************
  552. */
  553. #if OS_Q_POST_EN > 0u
  554. INT8U OSQPost (OS_EVENT *pevent,
  555. void *pmsg)
  556. {
  557. OS_Q *pq;
  558. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  559. OS_CPU_SR cpu_sr = 0u;
  560. #endif
  561. #if OS_ARG_CHK_EN > 0u
  562. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  563. return (OS_ERR_PEVENT_NULL);
  564. }
  565. #endif
  566. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  567. return (OS_ERR_EVENT_TYPE);
  568. }
  569. OS_ENTER_CRITICAL();
  570. if (pevent->OSEventGrp != 0u) { /* See if any task pending on queue */
  571. /* Ready highest priority task waiting on event */
  572. (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  573. OS_EXIT_CRITICAL();
  574. OS_Sched(); /* Find highest priority task ready to run */
  575. return (OS_ERR_NONE);
  576. }
  577. pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
  578. if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
  579. OS_EXIT_CRITICAL();
  580. return (OS_ERR_Q_FULL);
  581. }
  582. *pq->OSQIn++ = pmsg; /* Insert message into queue */
  583. pq->OSQEntries++; /* Update the nbr of entries in the queue */
  584. if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */
  585. pq->OSQIn = pq->OSQStart;
  586. }
  587. OS_EXIT_CRITICAL();
  588. return (OS_ERR_NONE);
  589. }
  590. #endif
  591. /*$PAGE*/
  592. /*
  593. *********************************************************************************************************
  594. * POST MESSAGE TO THE FRONT OF A QUEUE
  595. *
  596. * Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
  597. * the front instead of the end of the queue. Using OSQPostFront() allows you to send
  598. * 'priority' messages.
  599. *
  600. * Arguments : pevent is a pointer to the event control block associated with the desired queue
  601. *
  602. * pmsg is a pointer to the message to send.
  603. *
  604. * Returns : OS_ERR_NONE The call was successful and the message was sent
  605. * OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full.
  606. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
  607. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  608. *
  609. * Note(s) : As of V2.60, this function allows you to send NULL pointer messages.
  610. *********************************************************************************************************
  611. */
  612. #if OS_Q_POST_FRONT_EN > 0u
  613. INT8U OSQPostFront (OS_EVENT *pevent,
  614. void *pmsg)
  615. {
  616. OS_Q *pq;
  617. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  618. OS_CPU_SR cpu_sr = 0u;
  619. #endif
  620. #if OS_ARG_CHK_EN > 0u
  621. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  622. return (OS_ERR_PEVENT_NULL);
  623. }
  624. #endif
  625. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  626. return (OS_ERR_EVENT_TYPE);
  627. }
  628. OS_ENTER_CRITICAL();
  629. if (pevent->OSEventGrp != 0u) { /* See if any task pending on queue */
  630. /* Ready highest priority task waiting on event */
  631. (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  632. OS_EXIT_CRITICAL();
  633. OS_Sched(); /* Find highest priority task ready to run */
  634. return (OS_ERR_NONE);
  635. }
  636. pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
  637. if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
  638. OS_EXIT_CRITICAL();
  639. return (OS_ERR_Q_FULL);
  640. }
  641. if (pq->OSQOut == pq->OSQStart) { /* Wrap OUT ptr if we are at the 1st queue entry */
  642. pq->OSQOut = pq->OSQEnd;
  643. }
  644. pq->OSQOut--;
  645. *pq->OSQOut = pmsg; /* Insert message into queue */
  646. pq->OSQEntries++; /* Update the nbr of entries in the queue */
  647. OS_EXIT_CRITICAL();
  648. return (OS_ERR_NONE);
  649. }
  650. #endif
  651. /*$PAGE*/
  652. /*
  653. *********************************************************************************************************
  654. * POST MESSAGE TO A QUEUE
  655. *
  656. * Description: This function sends a message to a queue. This call has been added to reduce code size
  657. * since it can replace both OSQPost() and OSQPostFront(). Also, this function adds the
  658. * capability to broadcast a message to ALL tasks waiting on the message queue.
  659. *
  660. * Arguments : pevent is a pointer to the event control block associated with the desired queue
  661. *
  662. * pmsg is a pointer to the message to send.
  663. *
  664. * opt determines the type of POST performed:
  665. * OS_POST_OPT_NONE POST to a single waiting task
  666. * (Identical to OSQPost())
  667. * OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the queue
  668. * OS_POST_OPT_FRONT POST as LIFO (Simulates OSQPostFront())
  669. * OS_POST_OPT_NO_SCHED Indicates that the scheduler will NOT be invoked
  670. *
  671. * Returns : OS_ERR_NONE The call was successful and the message was sent
  672. * OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full.
  673. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
  674. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  675. *
  676. * Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the
  677. * interrupt disable time is proportional to the number of tasks waiting on the queue.
  678. *********************************************************************************************************
  679. */
  680. #if OS_Q_POST_OPT_EN > 0u
  681. INT8U OSQPostOpt (OS_EVENT *pevent,
  682. void *pmsg,
  683. INT8U opt)
  684. {
  685. OS_Q *pq;
  686. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  687. OS_CPU_SR cpu_sr = 0u;
  688. #endif
  689. #if OS_ARG_CHK_EN > 0u
  690. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  691. return (OS_ERR_PEVENT_NULL);
  692. }
  693. #endif
  694. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  695. return (OS_ERR_EVENT_TYPE);
  696. }
  697. OS_ENTER_CRITICAL();
  698. if (pevent->OSEventGrp != 0x00u) { /* See if any task pending on queue */
  699. if ((opt & OS_POST_OPT_BROADCAST) != 0x00u) { /* Do we need to post msg to ALL waiting tasks ? */
  700. while (pevent->OSEventGrp != 0u) { /* Yes, Post to ALL tasks waiting on queue */
  701. (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  702. }
  703. } else { /* No, Post to HPT waiting on queue */
  704. (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
  705. }
  706. OS_EXIT_CRITICAL();
  707. if ((opt & OS_POST_OPT_NO_SCHED) == 0u) { /* See if scheduler needs to be invoked */
  708. OS_Sched(); /* Find highest priority task ready to run */
  709. }
  710. return (OS_ERR_NONE);
  711. }
  712. pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
  713. if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
  714. OS_EXIT_CRITICAL();
  715. return (OS_ERR_Q_FULL);
  716. }
  717. if ((opt & OS_POST_OPT_FRONT) != 0x00u) { /* Do we post to the FRONT of the queue? */
  718. if (pq->OSQOut == pq->OSQStart) { /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
  719. pq->OSQOut = pq->OSQEnd; /* ... are at the 1st queue entry */
  720. }
  721. pq->OSQOut--;
  722. *pq->OSQOut = pmsg; /* Insert message into queue */
  723. } else { /* No, Post as FIFO */
  724. *pq->OSQIn++ = pmsg; /* Insert message into queue */
  725. if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */
  726. pq->OSQIn = pq->OSQStart;
  727. }
  728. }
  729. pq->OSQEntries++; /* Update the nbr of entries in the queue */
  730. OS_EXIT_CRITICAL();
  731. return (OS_ERR_NONE);
  732. }
  733. #endif
  734. /*$PAGE*/
  735. /*
  736. *********************************************************************************************************
  737. * QUERY A MESSAGE QUEUE
  738. *
  739. * Description: This function obtains information about a message queue.
  740. *
  741. * Arguments : pevent is a pointer to the event control block associated with the desired queue
  742. *
  743. * p_q_data is a pointer to a structure that will contain information about the message
  744. * queue.
  745. *
  746. * Returns : OS_ERR_NONE The call was successful and the message was sent
  747. * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non queue.
  748. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  749. * OS_ERR_PDATA_NULL If 'p_q_data' is a NULL pointer
  750. *********************************************************************************************************
  751. */
  752. #if OS_Q_QUERY_EN > 0u
  753. INT8U OSQQuery (OS_EVENT *pevent,
  754. OS_Q_DATA *p_q_data)
  755. {
  756. OS_Q *pq;
  757. INT8U i;
  758. OS_PRIO *psrc;
  759. OS_PRIO *pdest;
  760. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  761. OS_CPU_SR cpu_sr = 0u;
  762. #endif
  763. #if OS_ARG_CHK_EN > 0u
  764. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  765. return (OS_ERR_PEVENT_NULL);
  766. }
  767. if (p_q_data == (OS_Q_DATA *)0) { /* Validate 'p_q_data' */
  768. return (OS_ERR_PDATA_NULL);
  769. }
  770. #endif
  771. if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
  772. return (OS_ERR_EVENT_TYPE);
  773. }
  774. OS_ENTER_CRITICAL();
  775. p_q_data->OSEventGrp = pevent->OSEventGrp; /* Copy message queue wait list */
  776. psrc = &pevent->OSEventTbl[0];
  777. pdest = &p_q_data->OSEventTbl[0];
  778. for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
  779. *pdest++ = *psrc++;
  780. }
  781. pq = (OS_Q *)pevent->OSEventPtr;
  782. if (pq->OSQEntries > 0u) {
  783. p_q_data->OSMsg = *pq->OSQOut; /* Get next message to return if available */
  784. } else {
  785. p_q_data->OSMsg = (void *)0;
  786. }
  787. p_q_data->OSNMsgs = pq->OSQEntries;
  788. p_q_data->OSQSize = pq->OSQSize;
  789. OS_EXIT_CRITICAL();
  790. return (OS_ERR_NONE);
  791. }
  792. #endif /* OS_Q_QUERY_EN */
  793. /*$PAGE*/
  794. /*
  795. *********************************************************************************************************
  796. * QUEUE MODULE INITIALIZATION
  797. *
  798. * Description : This function is called by uC/OS-II to initialize the message queue module. Your
  799. * application MUST NOT call this function.
  800. *
  801. * Arguments : none
  802. *
  803. * Returns : none
  804. *
  805. * Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it.
  806. *********************************************************************************************************
  807. */
  808. void OS_QInit (void)
  809. {
  810. #if OS_MAX_QS == 1u
  811. OSQFreeList = &OSQTbl[0]; /* Only ONE queue! */
  812. OSQFreeList->OSQPtr = (OS_Q *)0;
  813. #endif
  814. #if OS_MAX_QS >= 2u
  815. INT16U ix;
  816. INT16U ix_next;
  817. OS_Q *pq1;
  818. OS_Q *pq2;
  819. OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl)); /* Clear the queue table */
  820. for (ix = 0u; ix < (OS_MAX_QS - 1u); ix++) { /* Init. list of free QUEUE control blocks */
  821. ix_next = ix + 1u;
  822. pq1 = &OSQTbl[ix];
  823. pq2 = &OSQTbl[ix_next];
  824. pq1->OSQPtr = pq2;
  825. }
  826. pq1 = &OSQTbl[ix];
  827. pq1->OSQPtr = (OS_Q *)0;
  828. OSQFreeList = &OSQTbl[0];
  829. #endif
  830. }
  831. #endif /* OS_Q_EN */