您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

680 行
30 KiB

  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. *
  6. * Copyright 1992-2021 Silicon Laboratories Inc. www.silabs.com
  7. *
  8. * SPDX-License-Identifier: APACHE-2.0
  9. *
  10. * This software is subject to an open source license and is distributed by
  11. * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
  12. * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
  13. *
  14. *********************************************************************************************************
  15. */
  16. /*
  17. *********************************************************************************************************
  18. *
  19. * SEMAPHORE MANAGEMENT
  20. *
  21. * Filename : os_sem.c
  22. * Version : V2.93.01
  23. *********************************************************************************************************
  24. */
  25. #ifndef OS_SEM_C
  26. #define OS_SEM_C
  27. #define MICRIUM_SOURCE
  28. #ifndef OS_MASTER_FILE
  29. #include <ucos_ii.h>
  30. #endif
  31. #if OS_SEM_EN > 0u
  32. /*
  33. *********************************************************************************************************
  34. * ACCEPT SEMAPHORE
  35. *
  36. * Description: This function checks the semaphore to see if a resource is available or, if an event
  37. * occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
  38. * resource is not available or the event did not occur.
  39. *
  40. * Arguments : pevent is a pointer to the event control block
  41. *
  42. * Returns : > 0 if the resource is available or the event did not occur the semaphore is
  43. * decremented to obtain the resource.
  44. * == 0 if the resource is not available or the event did not occur or,
  45. * if 'pevent' is a NULL pointer or,
  46. * if you didn't pass a pointer to a semaphore
  47. *********************************************************************************************************
  48. */
  49. #if OS_SEM_ACCEPT_EN > 0u
  50. INT16U OSSemAccept (OS_EVENT *pevent)
  51. {
  52. INT16U cnt;
  53. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  54. OS_CPU_SR cpu_sr = 0u;
  55. #endif
  56. #if OS_ARG_CHK_EN > 0u
  57. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  58. return (0u);
  59. }
  60. #endif
  61. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  62. return (0u);
  63. }
  64. OS_ENTER_CRITICAL();
  65. cnt = pevent->OSEventCnt;
  66. if (cnt > 0u) { /* See if resource is available */
  67. pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */
  68. }
  69. OS_EXIT_CRITICAL();
  70. return (cnt); /* Return semaphore count */
  71. }
  72. #endif
  73. /*
  74. *********************************************************************************************************
  75. * CREATE A SEMAPHORE
  76. *
  77. * Description: This function creates a semaphore.
  78. *
  79. * Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is
  80. * available (or no event has occurred). You initialize the semaphore to a
  81. * non-zero value to specify how many resources are available (e.g. if you have
  82. * 10 resources, you would initialize the semaphore to 10).
  83. *
  84. * Returns : != (void *)0 is a pointer to the event control block (OS_EVENT) associated with the
  85. * created semaphore
  86. * == (void *)0 if no event control blocks were available
  87. *********************************************************************************************************
  88. */
  89. OS_EVENT *OSSemCreate (INT16U cnt)
  90. {
  91. OS_EVENT *pevent;
  92. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  93. OS_CPU_SR cpu_sr = 0u;
  94. #endif
  95. #ifdef OS_SAFETY_CRITICAL_IEC61508
  96. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  97. OS_SAFETY_CRITICAL_EXCEPTION();
  98. return ((OS_EVENT *)0);
  99. }
  100. #endif
  101. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  102. return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
  103. }
  104. OS_ENTER_CRITICAL();
  105. pevent = OSEventFreeList; /* Get next free event control block */
  106. if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
  107. OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  108. }
  109. OS_EXIT_CRITICAL();
  110. if (pevent != (OS_EVENT *)0) { /* Get an event control block */
  111. pevent->OSEventType = OS_EVENT_TYPE_SEM;
  112. pevent->OSEventCnt = cnt; /* Set semaphore value */
  113. pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */
  114. #if OS_EVENT_NAME_EN > 0u
  115. pevent->OSEventName = (INT8U *)(void *)"?";
  116. #endif
  117. OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */
  118. OS_TRACE_SEM_CREATE(pevent, pevent->OSEventName);
  119. }
  120. return (pevent);
  121. }
  122. /*
  123. *********************************************************************************************************
  124. * DELETE A SEMAPHORE
  125. *
  126. * Description: This function deletes a semaphore and readies all tasks pending on the semaphore.
  127. *
  128. * Arguments : pevent is a pointer to the event control block associated with the desired
  129. * semaphore.
  130. *
  131. * opt determines delete options as follows:
  132. * opt == OS_DEL_NO_PEND Delete semaphore ONLY if no task pending
  133. * opt == OS_DEL_ALWAYS Deletes the semaphore even if tasks are waiting.
  134. * In this case, all the tasks pending will be readied.
  135. *
  136. * perr is a pointer to an error code that can contain one of the following values:
  137. * OS_ERR_NONE The call was successful and the semaphore was
  138. * deleted
  139. * OS_ERR_DEL_ISR If you attempted to delete the semaphore from an
  140. * ISR
  141. * OS_ERR_ILLEGAL_DEL_RUN_TIME If you tried to delete the semaphore after
  142. * safety critical operation started.
  143. * OS_ERR_INVALID_OPT An invalid option was specified
  144. * OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore
  145. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
  146. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  147. *
  148. * Returns : pevent upon error
  149. * (OS_EVENT *)0 if the semaphore was successfully deleted.
  150. *
  151. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  152. * the semaphore MUST check the return code of OSSemPend().
  153. * 2) OSSemAccept() callers will not know that the intended semaphore has been deleted unless
  154. * they check 'pevent' to see that it's a NULL pointer.
  155. * 3) This call can potentially disable interrupts for a long time. The interrupt disable
  156. * time is directly proportional to the number of tasks waiting on the semaphore.
  157. * 4) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in
  158. * applications where the semaphore is used for mutual exclusion because the resource(s)
  159. * will no longer be guarded by the semaphore.
  160. * 5) All tasks that were waiting for the semaphore will be readied and returned an
  161. * OS_ERR_PEND_ABORT if OSSemDel() was called with OS_DEL_ALWAYS
  162. *********************************************************************************************************
  163. */
  164. #if OS_SEM_DEL_EN > 0u
  165. OS_EVENT *OSSemDel (OS_EVENT *pevent,
  166. INT8U opt,
  167. INT8U *perr)
  168. {
  169. BOOLEAN tasks_waiting;
  170. OS_EVENT *pevent_return;
  171. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  172. OS_CPU_SR cpu_sr = 0u;
  173. #endif
  174. #ifdef OS_SAFETY_CRITICAL
  175. if (perr == (INT8U *)0) {
  176. OS_SAFETY_CRITICAL_EXCEPTION();
  177. return ((OS_EVENT *)0);
  178. }
  179. #endif
  180. #ifdef OS_SAFETY_CRITICAL_IEC61508
  181. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  182. OS_SAFETY_CRITICAL_EXCEPTION();
  183. *perr = OS_ERR_ILLEGAL_DEL_RUN_TIME;
  184. return ((OS_EVENT *)0);
  185. }
  186. #endif
  187. #if OS_ARG_CHK_EN > 0u
  188. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  189. *perr = OS_ERR_PEVENT_NULL;
  190. return (pevent);
  191. }
  192. #endif
  193. OS_TRACE_SEM_DEL_ENTER(pevent, opt);
  194. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  195. *perr = OS_ERR_EVENT_TYPE;
  196. OS_TRACE_SEM_DEL_EXIT(*perr);
  197. return (pevent);
  198. }
  199. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  200. *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  201. OS_TRACE_SEM_DEL_EXIT(*perr);
  202. return (pevent);
  203. }
  204. OS_ENTER_CRITICAL();
  205. if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on semaphore */
  206. tasks_waiting = OS_TRUE; /* Yes */
  207. } else {
  208. tasks_waiting = OS_FALSE; /* No */
  209. }
  210. switch (opt) {
  211. case OS_DEL_NO_PEND: /* Delete semaphore only if no task waiting */
  212. if (tasks_waiting == OS_FALSE) {
  213. #if OS_EVENT_NAME_EN > 0u
  214. pevent->OSEventName = (INT8U *)(void *)"?";
  215. #endif
  216. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  217. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  218. pevent->OSEventCnt = 0u;
  219. OSEventFreeList = pevent; /* Get next free event control block */
  220. OS_EXIT_CRITICAL();
  221. *perr = OS_ERR_NONE;
  222. pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
  223. } else {
  224. OS_EXIT_CRITICAL();
  225. *perr = OS_ERR_TASK_WAITING;
  226. pevent_return = pevent;
  227. }
  228. break;
  229. case OS_DEL_ALWAYS: /* Always delete the semaphore */
  230. while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for semaphore */
  231. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
  232. }
  233. #if OS_EVENT_NAME_EN > 0u
  234. pevent->OSEventName = (INT8U *)(void *)"?";
  235. #endif
  236. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  237. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  238. pevent->OSEventCnt = 0u;
  239. OSEventFreeList = pevent; /* Get next free event control block */
  240. OS_EXIT_CRITICAL();
  241. if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
  242. OS_Sched(); /* Find highest priority task ready to run */
  243. }
  244. *perr = OS_ERR_NONE;
  245. pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
  246. break;
  247. default:
  248. OS_EXIT_CRITICAL();
  249. *perr = OS_ERR_INVALID_OPT;
  250. pevent_return = pevent;
  251. break;
  252. }
  253. OS_TRACE_SEM_DEL_EXIT(*perr);
  254. return (pevent_return);
  255. }
  256. #endif
  257. /*
  258. *********************************************************************************************************
  259. * PEND ON SEMAPHORE
  260. *
  261. * Description: This function waits for a semaphore.
  262. *
  263. * Arguments : pevent is a pointer to the event control block associated with the desired
  264. * semaphore.
  265. *
  266. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  267. * wait for the resource up to the amount of time specified by this argument.
  268. * If you specify 0, however, your task will wait forever at the specified
  269. * semaphore or, until the resource becomes available (or the event occurs).
  270. *
  271. * perr is a pointer to where an error message will be deposited. Possible error
  272. * messages are:
  273. *
  274. * OS_ERR_NONE The call was successful and your task owns the resource
  275. * or, the event you are waiting for occurred.
  276. * OS_ERR_TIMEOUT The semaphore was not received within the specified
  277. * 'timeout'.
  278. * OS_ERR_PEND_ABORT The wait on the semaphore was aborted.
  279. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
  280. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  281. * would lead to a suspension.
  282. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  283. * OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
  284. *
  285. * Returns : none
  286. *********************************************************************************************************
  287. */
  288. void OSSemPend (OS_EVENT *pevent,
  289. INT32U timeout,
  290. INT8U *perr)
  291. {
  292. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  293. OS_CPU_SR cpu_sr = 0u;
  294. #endif
  295. #ifdef OS_SAFETY_CRITICAL
  296. if (perr == (INT8U *)0) {
  297. OS_SAFETY_CRITICAL_EXCEPTION();
  298. return;
  299. }
  300. #endif
  301. #if OS_ARG_CHK_EN > 0u
  302. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  303. *perr = OS_ERR_PEVENT_NULL;
  304. return;
  305. }
  306. #endif
  307. OS_TRACE_SEM_PEND_ENTER(pevent, timeout);
  308. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  309. *perr = OS_ERR_EVENT_TYPE;
  310. OS_TRACE_SEM_PEND_EXIT(*perr);
  311. return;
  312. }
  313. if (OSIntNesting > 0u) { /* See if called from ISR ... */
  314. *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  315. OS_TRACE_SEM_PEND_EXIT(*perr);
  316. return;
  317. }
  318. if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */
  319. *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
  320. OS_TRACE_SEM_PEND_EXIT(*perr);
  321. return;
  322. }
  323. OS_ENTER_CRITICAL();
  324. if (pevent->OSEventCnt > 0u) { /* If sem. is positive, resource available ... */
  325. pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */
  326. OS_EXIT_CRITICAL();
  327. *perr = OS_ERR_NONE;
  328. OS_TRACE_SEM_PEND_EXIT(*perr);
  329. return;
  330. }
  331. /* Otherwise, must wait until event occurs */
  332. OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */
  333. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
  334. OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
  335. OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  336. OS_EXIT_CRITICAL();
  337. OS_Sched(); /* Find next highest priority task ready */
  338. OS_ENTER_CRITICAL();
  339. switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
  340. case OS_STAT_PEND_OK:
  341. *perr = OS_ERR_NONE;
  342. break;
  343. case OS_STAT_PEND_ABORT:
  344. *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
  345. break;
  346. case OS_STAT_PEND_TO:
  347. default:
  348. OS_EventTaskRemove(OSTCBCur, pevent);
  349. *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
  350. break;
  351. }
  352. OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
  353. OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
  354. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
  355. #if (OS_EVENT_MULTI_EN > 0u)
  356. OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  357. OSTCBCur->OSTCBEventMultiRdy = (OS_EVENT *)0;
  358. #endif
  359. OS_EXIT_CRITICAL();
  360. OS_TRACE_SEM_PEND_EXIT(*perr);
  361. }
  362. /*
  363. *********************************************************************************************************
  364. * ABORT WAITING ON A SEMAPHORE
  365. *
  366. * Description: This function aborts & readies any tasks currently waiting on a semaphore. This function
  367. * should be used to fault-abort the wait on the semaphore, rather than to normally signal
  368. * the semaphore via OSSemPost().
  369. *
  370. * Arguments : pevent is a pointer to the event control block associated with the desired
  371. * semaphore.
  372. *
  373. * opt determines the type of ABORT performed:
  374. * OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the
  375. * semaphore
  376. * OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the
  377. * semaphore
  378. *
  379. * perr is a pointer to where an error message will be deposited. Possible error
  380. * messages are:
  381. *
  382. * OS_ERR_NONE No tasks were waiting on the semaphore.
  383. * OS_ERR_PEND_ABORT At least one task waiting on the semaphore was readied
  384. * and informed of the aborted wait; check return value
  385. * for the number of tasks whose wait on the semaphore
  386. * was aborted.
  387. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
  388. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  389. *
  390. * Returns : == 0 if no tasks were waiting on the semaphore, or upon error.
  391. * > 0 if one or more tasks waiting on the semaphore are now readied and informed.
  392. *********************************************************************************************************
  393. */
  394. #if OS_SEM_PEND_ABORT_EN > 0u
  395. INT8U OSSemPendAbort (OS_EVENT *pevent,
  396. INT8U opt,
  397. INT8U *perr)
  398. {
  399. INT8U nbr_tasks;
  400. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  401. OS_CPU_SR cpu_sr = 0u;
  402. #endif
  403. #ifdef OS_SAFETY_CRITICAL
  404. if (perr == (INT8U *)0) {
  405. OS_SAFETY_CRITICAL_EXCEPTION();
  406. return (0u);
  407. }
  408. #endif
  409. #if OS_ARG_CHK_EN > 0u
  410. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  411. *perr = OS_ERR_PEVENT_NULL;
  412. return (0u);
  413. }
  414. #endif
  415. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  416. *perr = OS_ERR_EVENT_TYPE;
  417. return (0u);
  418. }
  419. OS_ENTER_CRITICAL();
  420. if (pevent->OSEventGrp != 0u) { /* See if any task waiting on semaphore? */
  421. nbr_tasks = 0u;
  422. switch (opt) {
  423. case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */
  424. while (pevent->OSEventGrp != 0u) { /* Yes, ready ALL tasks waiting on semaphore */
  425. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
  426. nbr_tasks++;
  427. }
  428. break;
  429. case OS_PEND_OPT_NONE:
  430. default: /* No, ready HPT waiting on semaphore */
  431. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
  432. nbr_tasks++;
  433. break;
  434. }
  435. OS_EXIT_CRITICAL();
  436. OS_Sched(); /* Find HPT ready to run */
  437. *perr = OS_ERR_PEND_ABORT;
  438. return (nbr_tasks);
  439. }
  440. OS_EXIT_CRITICAL();
  441. *perr = OS_ERR_NONE;
  442. return (0u); /* No tasks waiting on semaphore */
  443. }
  444. #endif
  445. /*
  446. *********************************************************************************************************
  447. * POST TO A SEMAPHORE
  448. *
  449. * Description: This function signals a semaphore
  450. *
  451. * Arguments : pevent is a pointer to the event control block associated with the desired
  452. * semaphore.
  453. *
  454. * Returns : OS_ERR_NONE The call was successful and the semaphore was signaled.
  455. * OS_ERR_SEM_OVF If the semaphore count exceeded its limit. In other words, you have
  456. * signaled the semaphore more often than you waited on it with either
  457. * OSSemAccept() or OSSemPend().
  458. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
  459. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  460. *********************************************************************************************************
  461. */
  462. INT8U OSSemPost (OS_EVENT *pevent)
  463. {
  464. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  465. OS_CPU_SR cpu_sr = 0u;
  466. #endif
  467. #if OS_ARG_CHK_EN > 0u
  468. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  469. return (OS_ERR_PEVENT_NULL);
  470. }
  471. #endif
  472. OS_TRACE_SEM_POST_ENTER(pevent);
  473. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  474. OS_TRACE_SEM_POST_EXIT(OS_ERR_EVENT_TYPE);
  475. return (OS_ERR_EVENT_TYPE);
  476. }
  477. OS_ENTER_CRITICAL();
  478. if (pevent->OSEventGrp != 0u) { /* See if any task waiting for semaphore */
  479. /* Ready HPT waiting on event */
  480. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
  481. OS_EXIT_CRITICAL();
  482. OS_Sched(); /* Find HPT ready to run */
  483. OS_TRACE_SEM_POST_EXIT(OS_ERR_NONE);
  484. return (OS_ERR_NONE);
  485. }
  486. if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
  487. pevent->OSEventCnt++; /* Increment semaphore count to register event */
  488. OS_EXIT_CRITICAL();
  489. OS_TRACE_SEM_POST_EXIT(OS_ERR_NONE);
  490. return (OS_ERR_NONE);
  491. }
  492. OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
  493. OS_TRACE_SEM_POST_EXIT(OS_ERR_SEM_OVF);
  494. return (OS_ERR_SEM_OVF);
  495. }
  496. /*
  497. *********************************************************************************************************
  498. * QUERY A SEMAPHORE
  499. *
  500. * Description: This function obtains information about a semaphore
  501. *
  502. * Arguments : pevent is a pointer to the event control block associated with the desired
  503. * semaphore
  504. *
  505. * p_sem_data is a pointer to a structure that will contain information about the
  506. * semaphore.
  507. *
  508. * Returns : OS_ERR_NONE The call was successful and the message was sent
  509. * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non semaphore.
  510. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  511. * OS_ERR_PDATA_NULL If 'p_sem_data' is a NULL pointer
  512. *********************************************************************************************************
  513. */
  514. #if OS_SEM_QUERY_EN > 0u
  515. INT8U OSSemQuery (OS_EVENT *pevent,
  516. OS_SEM_DATA *p_sem_data)
  517. {
  518. INT8U i;
  519. OS_PRIO *psrc;
  520. OS_PRIO *pdest;
  521. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  522. OS_CPU_SR cpu_sr = 0u;
  523. #endif
  524. #if OS_ARG_CHK_EN > 0u
  525. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  526. return (OS_ERR_PEVENT_NULL);
  527. }
  528. if (p_sem_data == (OS_SEM_DATA *)0) { /* Validate 'p_sem_data' */
  529. return (OS_ERR_PDATA_NULL);
  530. }
  531. #endif
  532. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  533. return (OS_ERR_EVENT_TYPE);
  534. }
  535. OS_ENTER_CRITICAL();
  536. p_sem_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */
  537. psrc = &pevent->OSEventTbl[0];
  538. pdest = &p_sem_data->OSEventTbl[0];
  539. for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
  540. *pdest++ = *psrc++;
  541. }
  542. p_sem_data->OSCnt = pevent->OSEventCnt; /* Get semaphore count */
  543. OS_EXIT_CRITICAL();
  544. return (OS_ERR_NONE);
  545. }
  546. #endif /* OS_SEM_QUERY_EN */
  547. /*
  548. *********************************************************************************************************
  549. * SET SEMAPHORE
  550. *
  551. * Description: This function sets the semaphore count to the value specified as an argument. Typically,
  552. * this value would be 0.
  553. *
  554. * You would typically use this function when a semaphore is used as a signaling mechanism
  555. * and, you want to reset the count value.
  556. *
  557. * Arguments : pevent is a pointer to the event control block
  558. *
  559. * cnt is the new value for the semaphore count. You would pass 0 to reset the
  560. * semaphore count.
  561. *
  562. * perr is a pointer to an error code returned by the function as follows:
  563. *
  564. * OS_ERR_NONE The call was successful and the semaphore value was set.
  565. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
  566. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  567. * OS_ERR_TASK_WAITING If tasks are waiting on the semaphore.
  568. *********************************************************************************************************
  569. */
  570. #if OS_SEM_SET_EN > 0u
  571. void OSSemSet (OS_EVENT *pevent,
  572. INT16U cnt,
  573. INT8U *perr)
  574. {
  575. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  576. OS_CPU_SR cpu_sr = 0u;
  577. #endif
  578. #ifdef OS_SAFETY_CRITICAL
  579. if (perr == (INT8U *)0) {
  580. OS_SAFETY_CRITICAL_EXCEPTION();
  581. return;
  582. }
  583. #endif
  584. #if OS_ARG_CHK_EN > 0u
  585. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  586. *perr = OS_ERR_PEVENT_NULL;
  587. return;
  588. }
  589. #endif
  590. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  591. *perr = OS_ERR_EVENT_TYPE;
  592. return;
  593. }
  594. OS_ENTER_CRITICAL();
  595. *perr = OS_ERR_NONE;
  596. if (pevent->OSEventCnt > 0u) { /* See if semaphore already has a count */
  597. pevent->OSEventCnt = cnt; /* Yes, set it to the new value specified. */
  598. } else { /* No */
  599. if (pevent->OSEventGrp == 0u) { /* See if task(s) waiting? */
  600. pevent->OSEventCnt = cnt; /* No, OK to set the value */
  601. } else {
  602. *perr = OS_ERR_TASK_WAITING;
  603. }
  604. }
  605. OS_EXIT_CRITICAL();
  606. }
  607. #endif
  608. #endif /* OS_SEM_EN */
  609. #endif /* OS_SEM_C */