os_q.c 42 KB

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