rt_Mailbox.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*----------------------------------------------------------------------------
  2. * CMSIS-RTOS - RTX
  3. *----------------------------------------------------------------------------
  4. * Name: RT_MAILBOX.C
  5. * Purpose: Implements waits and wake-ups for mailbox messages
  6. * Rev.: V4.81
  7. *----------------------------------------------------------------------------
  8. *
  9. * Copyright (c) 1999-2009 KEIL, 2009-2017 ARM Germany GmbH. All rights reserved.
  10. *
  11. * SPDX-License-Identifier: Apache-2.0
  12. *
  13. * Licensed under the Apache License, Version 2.0 (the License); you may
  14. * not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  21. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. *---------------------------------------------------------------------------*/
  25. #include "rt_TypeDef.h"
  26. #include "RTX_Config.h"
  27. #include "rt_System.h"
  28. #include "rt_List.h"
  29. #include "rt_Mailbox.h"
  30. #include "rt_MemBox.h"
  31. #include "rt_Task.h"
  32. #include "rt_HAL_CM.h"
  33. /*----------------------------------------------------------------------------
  34. * Functions
  35. *---------------------------------------------------------------------------*/
  36. /*--------------------------- rt_mbx_init -----------------------------------*/
  37. void rt_mbx_init (OS_ID mailbox, U16 mbx_size) {
  38. /* Initialize a mailbox */
  39. P_MCB p_MCB = mailbox;
  40. p_MCB->cb_type = MCB;
  41. p_MCB->state = 0U;
  42. p_MCB->isr_st = 0U;
  43. p_MCB->p_lnk = NULL;
  44. p_MCB->first = 0U;
  45. p_MCB->last = 0U;
  46. p_MCB->count = 0U;
  47. p_MCB->size = (U16)((mbx_size - (sizeof(struct OS_MCB) - (sizeof(void *))))
  48. / sizeof(void *));
  49. }
  50. /*--------------------------- rt_mbx_send -----------------------------------*/
  51. OS_RESULT rt_mbx_send (OS_ID mailbox, void *p_msg, U16 timeout) {
  52. /* Send message to a mailbox */
  53. P_MCB p_MCB = mailbox;
  54. P_TCB p_TCB;
  55. if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 1U)) {
  56. /* A task is waiting for message */
  57. p_TCB = rt_get_first ((P_XCB)p_MCB);
  58. #ifdef __CMSIS_RTOS
  59. rt_ret_val2(p_TCB, 0x10U/*osEventMessage*/, (U32)p_msg);
  60. #else
  61. *p_TCB->msg = p_msg;
  62. rt_ret_val (p_TCB, OS_R_MBX);
  63. #endif
  64. rt_rmv_dly (p_TCB);
  65. rt_dispatch (p_TCB);
  66. }
  67. else {
  68. /* Store message in mailbox queue */
  69. if (p_MCB->count == p_MCB->size) {
  70. /* No free message entry, wait for one. If message queue is full, */
  71. /* then no task is waiting for message. The 'p_MCB->p_lnk' list */
  72. /* pointer can now be reused for send message waits task list. */
  73. if (timeout == 0U) {
  74. return (OS_R_TMO);
  75. }
  76. if (p_MCB->p_lnk != NULL) {
  77. rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
  78. }
  79. else {
  80. p_MCB->p_lnk = os_tsk.run;
  81. os_tsk.run->p_lnk = NULL;
  82. os_tsk.run->p_rlnk = (P_TCB)p_MCB;
  83. /* Task is waiting to send a message */
  84. p_MCB->state = 2U;
  85. }
  86. os_tsk.run->msg = p_msg;
  87. rt_block (timeout, WAIT_MBX);
  88. return (OS_R_TMO);
  89. }
  90. /* Yes, there is a free entry in a mailbox. */
  91. p_MCB->msg[p_MCB->first] = p_msg;
  92. rt_inc (&p_MCB->count);
  93. if (++p_MCB->first == p_MCB->size) {
  94. p_MCB->first = 0U;
  95. }
  96. }
  97. return (OS_R_OK);
  98. }
  99. /*--------------------------- rt_mbx_wait -----------------------------------*/
  100. OS_RESULT rt_mbx_wait (OS_ID mailbox, void **message, U16 timeout) {
  101. /* Receive a message; possibly wait for it */
  102. P_MCB p_MCB = mailbox;
  103. P_TCB p_TCB;
  104. /* If a message is available in the fifo buffer */
  105. /* remove it from the fifo buffer and return. */
  106. if (p_MCB->count) {
  107. *message = p_MCB->msg[p_MCB->last];
  108. if (++p_MCB->last == p_MCB->size) {
  109. p_MCB->last = 0U;
  110. }
  111. if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 2U)) {
  112. /* A task is waiting to send message */
  113. p_TCB = rt_get_first ((P_XCB)p_MCB);
  114. #ifdef __CMSIS_RTOS
  115. rt_ret_val(p_TCB, 0U/*osOK*/);
  116. #else
  117. rt_ret_val(p_TCB, OS_R_OK);
  118. #endif
  119. p_MCB->msg[p_MCB->first] = p_TCB->msg;
  120. if (++p_MCB->first == p_MCB->size) {
  121. p_MCB->first = 0U;
  122. }
  123. rt_rmv_dly (p_TCB);
  124. rt_dispatch (p_TCB);
  125. }
  126. else {
  127. rt_dec (&p_MCB->count);
  128. }
  129. return (OS_R_OK);
  130. }
  131. /* No message available: wait for one */
  132. if (timeout == 0U) {
  133. return (OS_R_TMO);
  134. }
  135. if (p_MCB->p_lnk != NULL) {
  136. rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
  137. }
  138. else {
  139. p_MCB->p_lnk = os_tsk.run;
  140. os_tsk.run->p_lnk = NULL;
  141. os_tsk.run->p_rlnk = (P_TCB)p_MCB;
  142. /* Task is waiting to receive a message */
  143. p_MCB->state = 1U;
  144. }
  145. rt_block(timeout, WAIT_MBX);
  146. #ifndef __CMSIS_RTOS
  147. os_tsk.run->msg = message;
  148. #endif
  149. return (OS_R_TMO);
  150. }
  151. /*--------------------------- rt_mbx_check ----------------------------------*/
  152. OS_RESULT rt_mbx_check (OS_ID mailbox) {
  153. /* Check for free space in a mailbox. Returns the number of messages */
  154. /* that can be stored to a mailbox. It returns 0 when mailbox is full. */
  155. P_MCB p_MCB = mailbox;
  156. return ((U32)(p_MCB->size - p_MCB->count));
  157. }
  158. /*--------------------------- isr_mbx_send ----------------------------------*/
  159. void isr_mbx_send (OS_ID mailbox, void *p_msg) {
  160. /* Same function as "os_mbx_send", but to be called by ISRs. */
  161. P_MCB p_MCB = mailbox;
  162. rt_psq_enq (p_MCB, (U32)p_msg);
  163. rt_psh_req ();
  164. }
  165. /*--------------------------- isr_mbx_receive -------------------------------*/
  166. OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message) {
  167. /* Receive a message in the interrupt function. The interrupt function */
  168. /* should not wait for a message since this would block the rtx os. */
  169. P_MCB p_MCB = mailbox;
  170. if (p_MCB->count) {
  171. /* A message is available in the fifo buffer. */
  172. *message = p_MCB->msg[p_MCB->last];
  173. if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 2U)) {
  174. /* A task is locked waiting to send message */
  175. rt_psq_enq (p_MCB, 0U);
  176. rt_psh_req ();
  177. }
  178. rt_dec (&p_MCB->count);
  179. if (++p_MCB->last == p_MCB->size) {
  180. p_MCB->last = 0U;
  181. }
  182. return (OS_R_MBX);
  183. }
  184. return (OS_R_OK);
  185. }
  186. /*--------------------------- rt_mbx_psh ------------------------------------*/
  187. void rt_mbx_psh (P_MCB p_CB, void *p_msg) {
  188. /* Store the message to the mailbox queue or pass it to task directly. */
  189. P_TCB p_TCB;
  190. void *mem;
  191. if (p_CB->p_lnk != NULL) switch (p_CB->state) {
  192. #ifdef __CMSIS_RTOS
  193. case 3:
  194. /* Task is waiting to allocate memory, remove it from the waiting list */
  195. mem = rt_alloc_box(p_msg);
  196. if (mem == NULL) { break; }
  197. p_TCB = rt_get_first ((P_XCB)p_CB);
  198. rt_ret_val(p_TCB, (U32)mem);
  199. p_TCB->state = READY;
  200. rt_rmv_dly (p_TCB);
  201. rt_put_prio (&os_rdy, p_TCB);
  202. break;
  203. #endif
  204. case 2:
  205. /* Task is waiting to send a message, remove it from the waiting list */
  206. p_TCB = rt_get_first ((P_XCB)p_CB);
  207. #ifdef __CMSIS_RTOS
  208. rt_ret_val(p_TCB, 0U/*osOK*/);
  209. #else
  210. rt_ret_val(p_TCB, OS_R_OK);
  211. #endif
  212. p_CB->msg[p_CB->first] = p_TCB->msg;
  213. rt_inc (&p_CB->count);
  214. if (++p_CB->first == p_CB->size) {
  215. p_CB->first = 0U;
  216. }
  217. p_TCB->state = READY;
  218. rt_rmv_dly (p_TCB);
  219. rt_put_prio (&os_rdy, p_TCB);
  220. break;
  221. case 1:
  222. /* Task is waiting for a message, pass the message to the task directly */
  223. p_TCB = rt_get_first ((P_XCB)p_CB);
  224. #ifdef __CMSIS_RTOS
  225. rt_ret_val2(p_TCB, 0x10U/*osEventMessage*/, (U32)p_msg);
  226. #else
  227. *p_TCB->msg = p_msg;
  228. rt_ret_val (p_TCB, OS_R_MBX);
  229. #endif
  230. p_TCB->state = READY;
  231. rt_rmv_dly (p_TCB);
  232. rt_put_prio (&os_rdy, p_TCB);
  233. break;
  234. default:
  235. break;
  236. } else {
  237. /* No task is waiting for a message, store it to the mailbox queue */
  238. if (p_CB->count < p_CB->size) {
  239. p_CB->msg[p_CB->first] = p_msg;
  240. rt_inc (&p_CB->count);
  241. if (++p_CB->first == p_CB->size) {
  242. p_CB->first = 0U;
  243. }
  244. }
  245. else {
  246. os_error (OS_ERR_MBX_OVF);
  247. }
  248. }
  249. }
  250. /*----------------------------------------------------------------------------
  251. * end of file
  252. *---------------------------------------------------------------------------*/