rtx_msgqueue.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  1. /*
  2. * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * -----------------------------------------------------------------------------
  19. *
  20. * Project: CMSIS-RTOS RTX
  21. * Title: Message Queue functions
  22. *
  23. * -----------------------------------------------------------------------------
  24. */
  25. #include "rtx_lib.h"
  26. // OS Runtime Object Memory Usage
  27. #ifdef RTX_OBJ_MEM_USAGE
  28. osRtxObjectMemUsage_t osRtxMessageQueueMemUsage \
  29. __attribute__((section(".data.os.msgqueue.obj"))) =
  30. { 0U, 0U, 0U };
  31. #endif
  32. // ==== Helper functions ====
  33. /// Put a Message into Queue sorted by Priority (Highest at Head).
  34. /// \param[in] mq message queue object.
  35. /// \param[in] msg message object.
  36. static void MessageQueuePut (os_message_queue_t *mq, os_message_t *msg) {
  37. #if (EXCLUSIVE_ACCESS == 0)
  38. uint32_t primask = __get_PRIMASK();
  39. #endif
  40. os_message_t *prev, *next;
  41. if (mq->msg_last != NULL) {
  42. prev = mq->msg_last;
  43. next = NULL;
  44. while ((prev != NULL) && (prev->priority < msg->priority)) {
  45. next = prev;
  46. prev = prev->prev;
  47. }
  48. msg->prev = prev;
  49. msg->next = next;
  50. if (prev != NULL) {
  51. prev->next = msg;
  52. } else {
  53. mq->msg_first = msg;
  54. }
  55. if (next != NULL) {
  56. next->prev = msg;
  57. } else {
  58. mq->msg_last = msg;
  59. }
  60. } else {
  61. msg->prev = NULL;
  62. msg->next = NULL;
  63. mq->msg_first= msg;
  64. mq->msg_last = msg;
  65. }
  66. #if (EXCLUSIVE_ACCESS == 0)
  67. __disable_irq();
  68. mq->msg_count++;
  69. if (primask == 0U) {
  70. __enable_irq();
  71. }
  72. #else
  73. (void)atomic_inc32(&mq->msg_count);
  74. #endif
  75. }
  76. /// Get a Message from Queue with Highest Priority.
  77. /// \param[in] mq message queue object.
  78. /// \return message object or NULL.
  79. static os_message_t *MessageQueueGet (os_message_queue_t *mq) {
  80. #if (EXCLUSIVE_ACCESS == 0)
  81. uint32_t primask = __get_PRIMASK();
  82. #endif
  83. os_message_t *msg;
  84. uint32_t count;
  85. uint8_t flags;
  86. #if (EXCLUSIVE_ACCESS == 0)
  87. __disable_irq();
  88. count = mq->msg_count;
  89. if (count != 0U) {
  90. mq->msg_count--;
  91. }
  92. if (primask == 0U) {
  93. __enable_irq();
  94. }
  95. #else
  96. count = atomic_dec32_nz(&mq->msg_count);
  97. #endif
  98. if (count != 0U) {
  99. msg = mq->msg_first;
  100. while (msg != NULL) {
  101. #if (EXCLUSIVE_ACCESS == 0)
  102. __disable_irq();
  103. flags = msg->flags;
  104. msg->flags = 1U;
  105. if (primask == 0U) {
  106. __enable_irq();
  107. }
  108. #else
  109. flags = atomic_wr8(&msg->flags, 1U);
  110. #endif
  111. if (flags == 0U) {
  112. break;
  113. }
  114. msg = msg->next;
  115. }
  116. } else {
  117. msg = NULL;
  118. }
  119. return msg;
  120. }
  121. /// Remove a Message from Queue
  122. /// \param[in] mq message queue object.
  123. /// \param[in] msg message object.
  124. static void MessageQueueRemove (os_message_queue_t *mq, const os_message_t *msg) {
  125. if (msg->prev != NULL) {
  126. msg->prev->next = msg->next;
  127. } else {
  128. mq->msg_first = msg->next;
  129. }
  130. if (msg->next != NULL) {
  131. msg->next->prev = msg->prev;
  132. } else {
  133. mq->msg_last = msg->prev;
  134. }
  135. }
  136. // ==== Post ISR processing ====
  137. /// Message Queue post ISR processing.
  138. /// \param[in] msg message object.
  139. static void osRtxMessageQueuePostProcess (os_message_t *msg) {
  140. os_message_queue_t *mq;
  141. os_message_t *msg0;
  142. os_thread_t *thread;
  143. const uint32_t *reg;
  144. const void *ptr_src;
  145. void *ptr_dst;
  146. if (msg->flags != 0U) {
  147. // Remove Message
  148. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  149. mq = *((os_message_queue_t **)(void *)&msg[1]);
  150. MessageQueueRemove(mq, msg);
  151. // Free memory
  152. msg->id = osRtxIdInvalid;
  153. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  154. // Check if Thread is waiting to send a Message
  155. if (mq->thread_list != NULL) {
  156. // Try to allocate memory
  157. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  158. msg0 = osRtxMemoryPoolAlloc(&mq->mp_info);
  159. if (msg0 != NULL) {
  160. // Wakeup waiting Thread with highest Priority
  161. thread = osRtxThreadListGet(osRtxObject(mq));
  162. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  163. // Copy Message (R1: const void *msg_ptr, R2: uint8_t msg_prio)
  164. reg = osRtxThreadRegPtr(thread);
  165. //lint -e{923} "cast from unsigned int to pointer"
  166. ptr_src = (const void *)reg[1];
  167. (void)memcpy(&msg0[1], ptr_src, mq->msg_size);
  168. // Store Message into Queue
  169. msg0->id = osRtxIdMessage;
  170. msg0->flags = 0U;
  171. msg0->priority = (uint8_t)reg[2];
  172. MessageQueuePut(mq, msg0);
  173. EvrRtxMessageQueueInserted(mq, ptr_src);
  174. }
  175. }
  176. } else {
  177. // New Message
  178. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  179. mq = (void *)msg->next;
  180. //lint -e{9087} "cast between pointers to different object types"
  181. ptr_src = (const void *)msg->prev;
  182. // Check if Thread is waiting to receive a Message
  183. if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
  184. EvrRtxMessageQueueInserted(mq, ptr_src);
  185. // Wakeup waiting Thread with highest Priority
  186. thread = osRtxThreadListGet(osRtxObject(mq));
  187. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  188. // Copy Message (R1: void *msg_ptr, R2: uint8_t *msg_prio)
  189. reg = osRtxThreadRegPtr(thread);
  190. //lint -e{923} "cast from unsigned int to pointer"
  191. ptr_dst = (void *)reg[1];
  192. (void)memcpy(ptr_dst, &msg[1], mq->msg_size);
  193. if (reg[2] != 0U) {
  194. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  195. *((uint8_t *)reg[2]) = msg->priority;
  196. }
  197. EvrRtxMessageQueueRetrieved(mq, ptr_dst);
  198. // Free memory
  199. msg->id = osRtxIdInvalid;
  200. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  201. } else {
  202. EvrRtxMessageQueueInserted(mq, ptr_src);
  203. MessageQueuePut(mq, msg);
  204. }
  205. }
  206. }
  207. // ==== Service Calls ====
  208. /// Create and Initialize a Message Queue object.
  209. /// \note API identical to osMessageQueueNew
  210. static osMessageQueueId_t svcRtxMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
  211. os_message_queue_t *mq;
  212. void *mq_mem;
  213. uint32_t mq_size;
  214. uint32_t block_size;
  215. uint32_t size;
  216. uint8_t flags;
  217. const char *name;
  218. // Check parameters
  219. if ((msg_count == 0U) || (msg_size == 0U) ||
  220. ((__CLZ(msg_count) + __CLZ(msg_size)) < 32U)) {
  221. EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
  222. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  223. return NULL;
  224. }
  225. block_size = ((msg_size + 3U) & ~3UL) + sizeof(os_message_t);
  226. size = msg_count * block_size;
  227. // Process attributes
  228. if (attr != NULL) {
  229. name = attr->name;
  230. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  231. mq = attr->cb_mem;
  232. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  233. mq_mem = attr->mq_mem;
  234. mq_size = attr->mq_size;
  235. if (mq != NULL) {
  236. //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
  237. if ((((uint32_t)mq & 3U) != 0U) || (attr->cb_size < sizeof(os_message_queue_t))) {
  238. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
  239. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  240. return NULL;
  241. }
  242. } else {
  243. if (attr->cb_size != 0U) {
  244. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
  245. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  246. return NULL;
  247. }
  248. }
  249. if (mq_mem != NULL) {
  250. //lint -e{923} "cast from pointer to unsigned int" [MISRA Note 7]
  251. if ((((uint32_t)mq_mem & 3U) != 0U) || (mq_size < size)) {
  252. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
  253. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  254. return NULL;
  255. }
  256. } else {
  257. if (mq_size != 0U) {
  258. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
  259. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  260. return NULL;
  261. }
  262. }
  263. } else {
  264. name = NULL;
  265. mq = NULL;
  266. mq_mem = NULL;
  267. }
  268. // Allocate object memory if not provided
  269. if (mq == NULL) {
  270. if (osRtxInfo.mpi.message_queue != NULL) {
  271. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  272. mq = osRtxMemoryPoolAlloc(osRtxInfo.mpi.message_queue);
  273. } else {
  274. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  275. mq = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_message_queue_t), 1U);
  276. }
  277. #ifdef RTX_OBJ_MEM_USAGE
  278. if (mq != NULL) {
  279. uint32_t used;
  280. osRtxMessageQueueMemUsage.cnt_alloc++;
  281. used = osRtxMessageQueueMemUsage.cnt_alloc - osRtxMessageQueueMemUsage.cnt_free;
  282. if (osRtxMessageQueueMemUsage.max_used < used) {
  283. osRtxMessageQueueMemUsage.max_used = used;
  284. }
  285. }
  286. #endif
  287. flags = osRtxFlagSystemObject;
  288. } else {
  289. flags = 0U;
  290. }
  291. // Allocate data memory if not provided
  292. if ((mq != NULL) && (mq_mem == NULL)) {
  293. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  294. mq_mem = osRtxMemoryAlloc(osRtxInfo.mem.mq_data, size, 0U);
  295. if (mq_mem == NULL) {
  296. if ((flags & osRtxFlagSystemObject) != 0U) {
  297. if (osRtxInfo.mpi.message_queue != NULL) {
  298. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
  299. } else {
  300. (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
  301. }
  302. #ifdef RTX_OBJ_MEM_USAGE
  303. osRtxMessageQueueMemUsage.cnt_free++;
  304. #endif
  305. }
  306. mq = NULL;
  307. } else {
  308. (void)memset(mq_mem, 0, size);
  309. }
  310. flags |= osRtxFlagSystemMemory;
  311. }
  312. if (mq != NULL) {
  313. // Initialize control block
  314. mq->id = osRtxIdMessageQueue;
  315. mq->flags = flags;
  316. mq->name = name;
  317. mq->thread_list = NULL;
  318. mq->msg_size = msg_size;
  319. mq->msg_count = 0U;
  320. mq->msg_first = NULL;
  321. mq->msg_last = NULL;
  322. (void)osRtxMemoryPoolInit(&mq->mp_info, msg_count, block_size, mq_mem);
  323. // Register post ISR processing function
  324. osRtxInfo.post_process.message = osRtxMessageQueuePostProcess;
  325. EvrRtxMessageQueueCreated(mq, mq->name);
  326. } else {
  327. EvrRtxMessageQueueError(NULL, (int32_t)osErrorNoMemory);
  328. }
  329. return mq;
  330. }
  331. /// Get name of a Message Queue object.
  332. /// \note API identical to osMessageQueueGetName
  333. static const char *svcRtxMessageQueueGetName (osMessageQueueId_t mq_id) {
  334. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  335. // Check parameters
  336. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  337. EvrRtxMessageQueueGetName(mq, NULL);
  338. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  339. return NULL;
  340. }
  341. EvrRtxMessageQueueGetName(mq, mq->name);
  342. return mq->name;
  343. }
  344. /// Put a Message into a Queue or timeout if Queue is full.
  345. /// \note API identical to osMessageQueuePut
  346. static osStatus_t svcRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  347. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  348. os_message_t *msg;
  349. os_thread_t *thread;
  350. uint32_t *reg;
  351. void *ptr;
  352. osStatus_t status;
  353. // Check parameters
  354. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
  355. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  356. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  357. return osErrorParameter;
  358. }
  359. // Check if Thread is waiting to receive a Message
  360. if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
  361. EvrRtxMessageQueueInserted(mq, msg_ptr);
  362. // Wakeup waiting Thread with highest Priority
  363. thread = osRtxThreadListGet(osRtxObject(mq));
  364. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  365. // Copy Message (R1: void *msg_ptr, R2: uint8_t *msg_prio)
  366. reg = osRtxThreadRegPtr(thread);
  367. //lint -e{923} "cast from unsigned int to pointer"
  368. ptr = (void *)reg[1];
  369. (void)memcpy(ptr, msg_ptr, mq->msg_size);
  370. if (reg[2] != 0U) {
  371. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  372. *((uint8_t *)reg[2]) = msg_prio;
  373. }
  374. EvrRtxMessageQueueRetrieved(mq, ptr);
  375. status = osOK;
  376. } else {
  377. // Try to allocate memory
  378. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  379. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  380. if (msg != NULL) {
  381. // Copy Message
  382. (void)memcpy(&msg[1], msg_ptr, mq->msg_size);
  383. // Put Message into Queue
  384. msg->id = osRtxIdMessage;
  385. msg->flags = 0U;
  386. msg->priority = msg_prio;
  387. MessageQueuePut(mq, msg);
  388. EvrRtxMessageQueueInserted(mq, msg_ptr);
  389. status = osOK;
  390. } else {
  391. // No memory available
  392. if (timeout != 0U) {
  393. EvrRtxMessageQueuePutPending(mq, msg_ptr, timeout);
  394. // Suspend current Thread
  395. if (osRtxThreadWaitEnter(osRtxThreadWaitingMessagePut, timeout)) {
  396. osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
  397. } else {
  398. EvrRtxMessageQueuePutTimeout(mq);
  399. }
  400. status = osErrorTimeout;
  401. } else {
  402. EvrRtxMessageQueueNotInserted(mq, msg_ptr);
  403. status = osErrorResource;
  404. }
  405. }
  406. }
  407. return status;
  408. }
  409. /// Get a Message from a Queue or timeout if Queue is empty.
  410. /// \note API identical to osMessageQueueGet
  411. static osStatus_t svcRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  412. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  413. os_message_t *msg;
  414. os_thread_t *thread;
  415. uint32_t *reg;
  416. const void *ptr;
  417. osStatus_t status;
  418. // Check parameters
  419. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
  420. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  421. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  422. return osErrorParameter;
  423. }
  424. // Get Message from Queue
  425. msg = MessageQueueGet(mq);
  426. if (msg != NULL) {
  427. MessageQueueRemove(mq, msg);
  428. // Copy Message
  429. (void)memcpy(msg_ptr, &msg[1], mq->msg_size);
  430. if (msg_prio != NULL) {
  431. *msg_prio = msg->priority;
  432. }
  433. EvrRtxMessageQueueRetrieved(mq, msg_ptr);
  434. // Free memory
  435. msg->id = osRtxIdInvalid;
  436. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  437. // Check if Thread is waiting to send a Message
  438. if (mq->thread_list != NULL) {
  439. // Try to allocate memory
  440. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  441. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  442. if (msg != NULL) {
  443. // Wakeup waiting Thread with highest Priority
  444. thread = osRtxThreadListGet(osRtxObject(mq));
  445. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  446. // Copy Message (R1: const void *msg_ptr, R2: uint8_t msg_prio)
  447. reg = osRtxThreadRegPtr(thread);
  448. //lint -e{923} "cast from unsigned int to pointer"
  449. ptr = (const void *)reg[1];
  450. (void)memcpy(&msg[1], ptr, mq->msg_size);
  451. // Store Message into Queue
  452. msg->id = osRtxIdMessage;
  453. msg->flags = 0U;
  454. msg->priority = (uint8_t)reg[2];
  455. MessageQueuePut(mq, msg);
  456. EvrRtxMessageQueueInserted(mq, ptr);
  457. }
  458. }
  459. status = osOK;
  460. } else {
  461. // No Message available
  462. if (timeout != 0U) {
  463. EvrRtxMessageQueueGetPending(mq, msg_ptr, timeout);
  464. // Suspend current Thread
  465. if (osRtxThreadWaitEnter(osRtxThreadWaitingMessageGet, timeout)) {
  466. osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
  467. } else {
  468. EvrRtxMessageQueueGetTimeout(mq);
  469. }
  470. status = osErrorTimeout;
  471. } else {
  472. EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
  473. status = osErrorResource;
  474. }
  475. }
  476. return status;
  477. }
  478. /// Get maximum number of messages in a Message Queue.
  479. /// \note API identical to osMessageQueueGetCapacity
  480. static uint32_t svcRtxMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
  481. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  482. // Check parameters
  483. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  484. EvrRtxMessageQueueGetCapacity(mq, 0U);
  485. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  486. return 0U;
  487. }
  488. EvrRtxMessageQueueGetCapacity(mq, mq->mp_info.max_blocks);
  489. return mq->mp_info.max_blocks;
  490. }
  491. /// Get maximum message size in a Memory Pool.
  492. /// \note API identical to osMessageQueueGetMsgSize
  493. static uint32_t svcRtxMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
  494. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  495. // Check parameters
  496. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  497. EvrRtxMessageQueueGetMsgSize(mq, 0U);
  498. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  499. return 0U;
  500. }
  501. EvrRtxMessageQueueGetMsgSize(mq, mq->msg_size);
  502. return mq->msg_size;
  503. }
  504. /// Get number of queued messages in a Message Queue.
  505. /// \note API identical to osMessageQueueGetCount
  506. static uint32_t svcRtxMessageQueueGetCount (osMessageQueueId_t mq_id) {
  507. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  508. // Check parameters
  509. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  510. EvrRtxMessageQueueGetCount(mq, 0U);
  511. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  512. return 0U;
  513. }
  514. EvrRtxMessageQueueGetCount(mq, mq->msg_count);
  515. return mq->msg_count;
  516. }
  517. /// Get number of available slots for messages in a Message Queue.
  518. /// \note API identical to osMessageQueueGetSpace
  519. static uint32_t svcRtxMessageQueueGetSpace (osMessageQueueId_t mq_id) {
  520. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  521. // Check parameters
  522. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  523. EvrRtxMessageQueueGetSpace(mq, 0U);
  524. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  525. return 0U;
  526. }
  527. EvrRtxMessageQueueGetSpace(mq, mq->mp_info.max_blocks - mq->msg_count);
  528. return (mq->mp_info.max_blocks - mq->msg_count);
  529. }
  530. /// Reset a Message Queue to initial empty state.
  531. /// \note API identical to osMessageQueueReset
  532. static osStatus_t svcRtxMessageQueueReset (osMessageQueueId_t mq_id) {
  533. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  534. os_message_t *msg;
  535. os_thread_t *thread;
  536. const uint32_t *reg;
  537. const void *ptr;
  538. // Check parameters
  539. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  540. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  541. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  542. return osErrorParameter;
  543. }
  544. // Remove Messages from Queue
  545. for (;;) {
  546. // Get Message from Queue
  547. msg = MessageQueueGet(mq);
  548. if (msg == NULL) {
  549. break;
  550. }
  551. MessageQueueRemove(mq, msg);
  552. EvrRtxMessageQueueRetrieved(mq, NULL);
  553. // Free memory
  554. msg->id = osRtxIdInvalid;
  555. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  556. }
  557. // Check if Threads are waiting to send Messages
  558. if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessagePut)) {
  559. do {
  560. // Try to allocate memory
  561. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  562. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  563. if (msg != NULL) {
  564. // Wakeup waiting Thread with highest Priority
  565. thread = osRtxThreadListGet(osRtxObject(mq));
  566. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  567. // Copy Message (R1: const void *msg_ptr, R2: uint8_t msg_prio)
  568. reg = osRtxThreadRegPtr(thread);
  569. //lint -e{923} "cast from unsigned int to pointer"
  570. ptr = (const void *)reg[1];
  571. (void)memcpy(&msg[1], ptr, mq->msg_size);
  572. // Store Message into Queue
  573. msg->id = osRtxIdMessage;
  574. msg->flags = 0U;
  575. msg->priority = (uint8_t)reg[2];
  576. MessageQueuePut(mq, msg);
  577. EvrRtxMessageQueueInserted(mq, ptr);
  578. }
  579. } while ((msg != NULL) && (mq->thread_list != NULL));
  580. osRtxThreadDispatch(NULL);
  581. }
  582. EvrRtxMessageQueueResetDone(mq);
  583. return osOK;
  584. }
  585. /// Delete a Message Queue object.
  586. /// \note API identical to osMessageQueueDelete
  587. static osStatus_t svcRtxMessageQueueDelete (osMessageQueueId_t mq_id) {
  588. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  589. os_thread_t *thread;
  590. // Check parameters
  591. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  592. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  593. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  594. return osErrorParameter;
  595. }
  596. // Unblock waiting threads
  597. if (mq->thread_list != NULL) {
  598. do {
  599. thread = osRtxThreadListGet(osRtxObject(mq));
  600. osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
  601. } while (mq->thread_list != NULL);
  602. osRtxThreadDispatch(NULL);
  603. }
  604. // Mark object as invalid
  605. mq->id = osRtxIdInvalid;
  606. // Free data memory
  607. if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
  608. (void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
  609. }
  610. // Free object memory
  611. if ((mq->flags & osRtxFlagSystemObject) != 0U) {
  612. if (osRtxInfo.mpi.message_queue != NULL) {
  613. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
  614. } else {
  615. (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
  616. }
  617. #ifdef RTX_OBJ_MEM_USAGE
  618. osRtxMessageQueueMemUsage.cnt_free++;
  619. #endif
  620. }
  621. EvrRtxMessageQueueDestroyed(mq);
  622. return osOK;
  623. }
  624. // Service Calls definitions
  625. //lint ++flb "Library Begin" [MISRA Note 11]
  626. SVC0_3(MessageQueueNew, osMessageQueueId_t, uint32_t, uint32_t, const osMessageQueueAttr_t *)
  627. SVC0_1(MessageQueueGetName, const char *, osMessageQueueId_t)
  628. SVC0_4(MessageQueuePut, osStatus_t, osMessageQueueId_t, const void *, uint8_t, uint32_t)
  629. SVC0_4(MessageQueueGet, osStatus_t, osMessageQueueId_t, void *, uint8_t *, uint32_t)
  630. SVC0_1(MessageQueueGetCapacity, uint32_t, osMessageQueueId_t)
  631. SVC0_1(MessageQueueGetMsgSize, uint32_t, osMessageQueueId_t)
  632. SVC0_1(MessageQueueGetCount, uint32_t, osMessageQueueId_t)
  633. SVC0_1(MessageQueueGetSpace, uint32_t, osMessageQueueId_t)
  634. SVC0_1(MessageQueueReset, osStatus_t, osMessageQueueId_t)
  635. SVC0_1(MessageQueueDelete, osStatus_t, osMessageQueueId_t)
  636. //lint --flb "Library End"
  637. // ==== ISR Calls ====
  638. /// Put a Message into a Queue or timeout if Queue is full.
  639. /// \note API identical to osMessageQueuePut
  640. __STATIC_INLINE
  641. osStatus_t isrRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  642. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  643. os_message_t *msg;
  644. osStatus_t status;
  645. // Check parameters
  646. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
  647. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  648. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  649. return osErrorParameter;
  650. }
  651. // Try to allocate memory
  652. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  653. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  654. if (msg != NULL) {
  655. // Copy Message
  656. (void)memcpy(&msg[1], msg_ptr, mq->msg_size);
  657. msg->id = osRtxIdMessage;
  658. msg->flags = 0U;
  659. msg->priority = msg_prio;
  660. // Register post ISR processing
  661. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  662. *((const void **)(void *)&msg->prev) = msg_ptr;
  663. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  664. *( (void **) &msg->next) = mq;
  665. osRtxPostProcess(osRtxObject(msg));
  666. EvrRtxMessageQueueInsertPending(mq, msg_ptr);
  667. status = osOK;
  668. } else {
  669. // No memory available
  670. EvrRtxMessageQueueNotInserted(mq, msg_ptr);
  671. status = osErrorResource;
  672. }
  673. return status;
  674. }
  675. /// Get a Message from a Queue or timeout if Queue is empty.
  676. /// \note API identical to osMessageQueueGet
  677. __STATIC_INLINE
  678. osStatus_t isrRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  679. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  680. os_message_t *msg;
  681. osStatus_t status;
  682. // Check parameters
  683. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
  684. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  685. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  686. return osErrorParameter;
  687. }
  688. // Get Message from Queue
  689. msg = MessageQueueGet(mq);
  690. if (msg != NULL) {
  691. // Copy Message
  692. memcpy(msg_ptr, &msg[1], mq->msg_size);
  693. if (msg_prio != NULL) {
  694. *msg_prio = msg->priority;
  695. }
  696. // Register post ISR processing
  697. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  698. *((os_message_queue_t **)(void *)&msg[1]) = mq;
  699. osRtxPostProcess(osRtxObject(msg));
  700. EvrRtxMessageQueueRetrieved(mq, msg_ptr);
  701. status = osOK;
  702. } else {
  703. // No Message available
  704. EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
  705. status = osErrorResource;
  706. }
  707. return status;
  708. }
  709. // ==== Library functions ====
  710. /// Create a Message Queue for the Timer Thread.
  711. int32_t osRtxMessageQueueTimerSetup (void) {
  712. int32_t ret = -1;
  713. osRtxInfo.timer.mq = osRtxMessageQueueId(
  714. svcRtxMessageQueueNew(osRtxConfig.timer_mq_mcnt, sizeof(os_timer_finfo_t), osRtxConfig.timer_mq_attr)
  715. );
  716. if (osRtxInfo.timer.mq != NULL) {
  717. ret = 0;
  718. }
  719. return ret;
  720. }
  721. // ==== Public API ====
  722. /// Create and Initialize a Message Queue object.
  723. osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
  724. osMessageQueueId_t mq_id;
  725. EvrRtxMessageQueueNew(msg_count, msg_size, attr);
  726. if (IsException() || IsIrqMasked()) {
  727. EvrRtxMessageQueueError(NULL, (int32_t)osErrorISR);
  728. mq_id = NULL;
  729. } else {
  730. mq_id = __svcMessageQueueNew(msg_count, msg_size, attr);
  731. }
  732. return mq_id;
  733. }
  734. /// Get name of a Message Queue object.
  735. const char *osMessageQueueGetName (osMessageQueueId_t mq_id) {
  736. const char *name;
  737. if (IsException() || IsIrqMasked()) {
  738. EvrRtxMessageQueueGetName(mq_id, NULL);
  739. name = NULL;
  740. } else {
  741. name = __svcMessageQueueGetName(mq_id);
  742. }
  743. return name;
  744. }
  745. /// Put a Message into a Queue or timeout if Queue is full.
  746. osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  747. osStatus_t status;
  748. EvrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  749. if (IsException() || IsIrqMasked()) {
  750. status = isrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  751. } else {
  752. status = __svcMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  753. }
  754. return status;
  755. }
  756. /// Get a Message from a Queue or timeout if Queue is empty.
  757. osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  758. osStatus_t status;
  759. EvrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  760. if (IsException() || IsIrqMasked()) {
  761. status = isrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  762. } else {
  763. status = __svcMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  764. }
  765. return status;
  766. }
  767. /// Get maximum number of messages in a Message Queue.
  768. uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
  769. uint32_t capacity;
  770. if (IsException() || IsIrqMasked()) {
  771. capacity = svcRtxMessageQueueGetCapacity(mq_id);
  772. } else {
  773. capacity = __svcMessageQueueGetCapacity(mq_id);
  774. }
  775. return capacity;
  776. }
  777. /// Get maximum message size in a Memory Pool.
  778. uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
  779. uint32_t msg_size;
  780. if (IsException() || IsIrqMasked()) {
  781. msg_size = svcRtxMessageQueueGetMsgSize(mq_id);
  782. } else {
  783. msg_size = __svcMessageQueueGetMsgSize(mq_id);
  784. }
  785. return msg_size;
  786. }
  787. /// Get number of queued messages in a Message Queue.
  788. uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
  789. uint32_t count;
  790. if (IsException() || IsIrqMasked()) {
  791. count = svcRtxMessageQueueGetCount(mq_id);
  792. } else {
  793. count = __svcMessageQueueGetCount(mq_id);
  794. }
  795. return count;
  796. }
  797. /// Get number of available slots for messages in a Message Queue.
  798. uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
  799. uint32_t space;
  800. if (IsException() || IsIrqMasked()) {
  801. space = svcRtxMessageQueueGetSpace(mq_id);
  802. } else {
  803. space = __svcMessageQueueGetSpace(mq_id);
  804. }
  805. return space;
  806. }
  807. /// Reset a Message Queue to initial empty state.
  808. osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
  809. osStatus_t status;
  810. EvrRtxMessageQueueReset(mq_id);
  811. if (IsException() || IsIrqMasked()) {
  812. EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
  813. status = osErrorISR;
  814. } else {
  815. status = __svcMessageQueueReset(mq_id);
  816. }
  817. return status;
  818. }
  819. /// Delete a Message Queue object.
  820. osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
  821. osStatus_t status;
  822. EvrRtxMessageQueueDelete(mq_id);
  823. if (IsException() || IsIrqMasked()) {
  824. EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
  825. status = osErrorISR;
  826. } else {
  827. status = __svcMessageQueueDelete(mq_id);
  828. }
  829. return status;
  830. }