/src/compiler/ucos-vs2008/UCOS_SIM/src/ucosii/os_q.c

http://ftk.googlecode.com/ · C · 765 lines · 454 code · 48 blank · 263 comment · 110 complexity · 080c3056e17cfdc01f0e6d4cb1fedf1b MD5 · raw file

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