rtx_msgqueue.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /*
  2. * Copyright (c) 2013-2019 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. #if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
  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 (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  164. reg = osRtxThreadRegPtr(thread);
  165. //lint -e{923} "cast from unsigned int to pointer"
  166. ptr_src = (const void *)reg[2];
  167. 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[3];
  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 (R2: void *msg_ptr, R3: uint8_t *msg_prio)
  189. reg = osRtxThreadRegPtr(thread);
  190. //lint -e{923} "cast from unsigned int to pointer"
  191. ptr_dst = (void *)reg[2];
  192. memcpy(ptr_dst, &msg[1], mq->msg_size);
  193. if (reg[3] != 0U) {
  194. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  195. *((uint8_t *)reg[3]) = 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. EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
  221. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  222. return NULL;
  223. }
  224. block_size = ((msg_size + 3U) & ~3UL) + sizeof(os_message_t);
  225. if ((__CLZ(msg_count) + __CLZ(block_size)) < 32U) {
  226. EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
  227. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  228. return NULL;
  229. }
  230. size = msg_count * block_size;
  231. // Process attributes
  232. if (attr != NULL) {
  233. name = attr->name;
  234. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  235. mq = attr->cb_mem;
  236. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  237. mq_mem = attr->mq_mem;
  238. mq_size = attr->mq_size;
  239. if (mq != NULL) {
  240. //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
  241. if ((((uint32_t)mq & 3U) != 0U) || (attr->cb_size < sizeof(os_message_queue_t))) {
  242. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
  243. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  244. return NULL;
  245. }
  246. } else {
  247. if (attr->cb_size != 0U) {
  248. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
  249. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  250. return NULL;
  251. }
  252. }
  253. if (mq_mem != NULL) {
  254. //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
  255. if ((((uint32_t)mq_mem & 3U) != 0U) || (mq_size < size)) {
  256. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
  257. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  258. return NULL;
  259. }
  260. } else {
  261. if (mq_size != 0U) {
  262. EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
  263. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  264. return NULL;
  265. }
  266. }
  267. } else {
  268. name = NULL;
  269. mq = NULL;
  270. mq_mem = NULL;
  271. }
  272. // Allocate object memory if not provided
  273. if (mq == NULL) {
  274. if (osRtxInfo.mpi.message_queue != NULL) {
  275. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  276. mq = osRtxMemoryPoolAlloc(osRtxInfo.mpi.message_queue);
  277. } else {
  278. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  279. mq = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_message_queue_t), 1U);
  280. }
  281. #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
  282. if (mq != NULL) {
  283. uint32_t used;
  284. osRtxMessageQueueMemUsage.cnt_alloc++;
  285. used = osRtxMessageQueueMemUsage.cnt_alloc - osRtxMessageQueueMemUsage.cnt_free;
  286. if (osRtxMessageQueueMemUsage.max_used < used) {
  287. osRtxMessageQueueMemUsage.max_used = used;
  288. }
  289. }
  290. #endif
  291. flags = osRtxFlagSystemObject;
  292. } else {
  293. flags = 0U;
  294. }
  295. // Allocate data memory if not provided
  296. if ((mq != NULL) && (mq_mem == NULL)) {
  297. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  298. mq_mem = osRtxMemoryAlloc(osRtxInfo.mem.mq_data, size, 0U);
  299. if (mq_mem == NULL) {
  300. if ((flags & osRtxFlagSystemObject) != 0U) {
  301. if (osRtxInfo.mpi.message_queue != NULL) {
  302. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
  303. } else {
  304. (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
  305. }
  306. #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
  307. osRtxMessageQueueMemUsage.cnt_free++;
  308. #endif
  309. }
  310. mq = NULL;
  311. } else {
  312. memset(mq_mem, 0, size);
  313. }
  314. flags |= osRtxFlagSystemMemory;
  315. }
  316. if (mq != NULL) {
  317. // Initialize control block
  318. mq->id = osRtxIdMessageQueue;
  319. mq->flags = flags;
  320. mq->name = name;
  321. mq->thread_list = NULL;
  322. mq->msg_size = msg_size;
  323. mq->msg_count = 0U;
  324. mq->msg_first = NULL;
  325. mq->msg_last = NULL;
  326. (void)osRtxMemoryPoolInit(&mq->mp_info, msg_count, block_size, mq_mem);
  327. // Register post ISR processing function
  328. osRtxInfo.post_process.message = osRtxMessageQueuePostProcess;
  329. EvrRtxMessageQueueCreated(mq, mq->name);
  330. } else {
  331. EvrRtxMessageQueueError(NULL, (int32_t)osErrorNoMemory);
  332. }
  333. return mq;
  334. }
  335. /// Get name of a Message Queue object.
  336. /// \note API identical to osMessageQueueGetName
  337. static const char *svcRtxMessageQueueGetName (osMessageQueueId_t mq_id) {
  338. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  339. // Check parameters
  340. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  341. EvrRtxMessageQueueGetName(mq, NULL);
  342. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  343. return NULL;
  344. }
  345. EvrRtxMessageQueueGetName(mq, mq->name);
  346. return mq->name;
  347. }
  348. /// Put a Message into a Queue or timeout if Queue is full.
  349. /// \note API identical to osMessageQueuePut
  350. static osStatus_t svcRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  351. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  352. os_message_t *msg;
  353. os_thread_t *thread;
  354. uint32_t *reg;
  355. void *ptr;
  356. osStatus_t status;
  357. // Check parameters
  358. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
  359. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  360. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  361. return osErrorParameter;
  362. }
  363. // Check if Thread is waiting to receive a Message
  364. if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
  365. EvrRtxMessageQueueInserted(mq, msg_ptr);
  366. // Wakeup waiting Thread with highest Priority
  367. thread = osRtxThreadListGet(osRtxObject(mq));
  368. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  369. // Copy Message (R2: void *msg_ptr, R3: uint8_t *msg_prio)
  370. reg = osRtxThreadRegPtr(thread);
  371. //lint -e{923} "cast from unsigned int to pointer"
  372. ptr = (void *)reg[2];
  373. memcpy(ptr, msg_ptr, mq->msg_size);
  374. if (reg[3] != 0U) {
  375. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  376. *((uint8_t *)reg[3]) = msg_prio;
  377. }
  378. EvrRtxMessageQueueRetrieved(mq, ptr);
  379. status = osOK;
  380. } else {
  381. // Try to allocate memory
  382. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  383. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  384. if (msg != NULL) {
  385. // Copy Message
  386. memcpy(&msg[1], msg_ptr, mq->msg_size);
  387. // Put Message into Queue
  388. msg->id = osRtxIdMessage;
  389. msg->flags = 0U;
  390. msg->priority = msg_prio;
  391. MessageQueuePut(mq, msg);
  392. EvrRtxMessageQueueInserted(mq, msg_ptr);
  393. status = osOK;
  394. } else {
  395. // No memory available
  396. if (timeout != 0U) {
  397. EvrRtxMessageQueuePutPending(mq, msg_ptr, timeout);
  398. // Suspend current Thread
  399. if (osRtxThreadWaitEnter(osRtxThreadWaitingMessagePut, timeout)) {
  400. osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
  401. // Save arguments (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  402. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  403. reg = (uint32_t *)(__get_PSP());
  404. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  405. reg[2] = (uint32_t)msg_ptr;
  406. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  407. reg[3] = (uint32_t)msg_prio;
  408. } else {
  409. EvrRtxMessageQueuePutTimeout(mq);
  410. }
  411. status = osErrorTimeout;
  412. } else {
  413. EvrRtxMessageQueueNotInserted(mq, msg_ptr);
  414. status = osErrorResource;
  415. }
  416. }
  417. }
  418. return status;
  419. }
  420. /// Get a Message from a Queue or timeout if Queue is empty.
  421. /// \note API identical to osMessageQueueGet
  422. static osStatus_t svcRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  423. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  424. os_message_t *msg;
  425. os_thread_t *thread;
  426. uint32_t *reg;
  427. const void *ptr;
  428. osStatus_t status;
  429. // Check parameters
  430. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
  431. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  432. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  433. return osErrorParameter;
  434. }
  435. // Get Message from Queue
  436. msg = MessageQueueGet(mq);
  437. if (msg != NULL) {
  438. MessageQueueRemove(mq, msg);
  439. // Copy Message
  440. memcpy(msg_ptr, &msg[1], mq->msg_size);
  441. if (msg_prio != NULL) {
  442. *msg_prio = msg->priority;
  443. }
  444. EvrRtxMessageQueueRetrieved(mq, msg_ptr);
  445. // Free memory
  446. msg->id = osRtxIdInvalid;
  447. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  448. // Check if Thread is waiting to send a Message
  449. if (mq->thread_list != NULL) {
  450. // Try to allocate memory
  451. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  452. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  453. if (msg != NULL) {
  454. // Wakeup waiting Thread with highest Priority
  455. thread = osRtxThreadListGet(osRtxObject(mq));
  456. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  457. // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  458. reg = osRtxThreadRegPtr(thread);
  459. //lint -e{923} "cast from unsigned int to pointer"
  460. ptr = (const void *)reg[2];
  461. memcpy(&msg[1], ptr, mq->msg_size);
  462. // Store Message into Queue
  463. msg->id = osRtxIdMessage;
  464. msg->flags = 0U;
  465. msg->priority = (uint8_t)reg[3];
  466. MessageQueuePut(mq, msg);
  467. EvrRtxMessageQueueInserted(mq, ptr);
  468. }
  469. }
  470. status = osOK;
  471. } else {
  472. // No Message available
  473. if (timeout != 0U) {
  474. EvrRtxMessageQueueGetPending(mq, msg_ptr, timeout);
  475. // Suspend current Thread
  476. if (osRtxThreadWaitEnter(osRtxThreadWaitingMessageGet, timeout)) {
  477. osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
  478. // Save arguments (R2: void *msg_ptr, R3: uint8_t *msg_prio)
  479. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  480. reg = (uint32_t *)(__get_PSP());
  481. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  482. reg[2] = (uint32_t)msg_ptr;
  483. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  484. reg[3] = (uint32_t)msg_prio;
  485. } else {
  486. EvrRtxMessageQueueGetTimeout(mq);
  487. }
  488. status = osErrorTimeout;
  489. } else {
  490. EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
  491. status = osErrorResource;
  492. }
  493. }
  494. return status;
  495. }
  496. /// Get maximum number of messages in a Message Queue.
  497. /// \note API identical to osMessageQueueGetCapacity
  498. static uint32_t svcRtxMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
  499. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  500. // Check parameters
  501. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  502. EvrRtxMessageQueueGetCapacity(mq, 0U);
  503. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  504. return 0U;
  505. }
  506. EvrRtxMessageQueueGetCapacity(mq, mq->mp_info.max_blocks);
  507. return mq->mp_info.max_blocks;
  508. }
  509. /// Get maximum message size in a Memory Pool.
  510. /// \note API identical to osMessageQueueGetMsgSize
  511. static uint32_t svcRtxMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
  512. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  513. // Check parameters
  514. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  515. EvrRtxMessageQueueGetMsgSize(mq, 0U);
  516. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  517. return 0U;
  518. }
  519. EvrRtxMessageQueueGetMsgSize(mq, mq->msg_size);
  520. return mq->msg_size;
  521. }
  522. /// Get number of queued messages in a Message Queue.
  523. /// \note API identical to osMessageQueueGetCount
  524. static uint32_t svcRtxMessageQueueGetCount (osMessageQueueId_t mq_id) {
  525. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  526. // Check parameters
  527. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  528. EvrRtxMessageQueueGetCount(mq, 0U);
  529. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  530. return 0U;
  531. }
  532. EvrRtxMessageQueueGetCount(mq, mq->msg_count);
  533. return mq->msg_count;
  534. }
  535. /// Get number of available slots for messages in a Message Queue.
  536. /// \note API identical to osMessageQueueGetSpace
  537. static uint32_t svcRtxMessageQueueGetSpace (osMessageQueueId_t mq_id) {
  538. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  539. // Check parameters
  540. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  541. EvrRtxMessageQueueGetSpace(mq, 0U);
  542. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  543. return 0U;
  544. }
  545. EvrRtxMessageQueueGetSpace(mq, mq->mp_info.max_blocks - mq->msg_count);
  546. return (mq->mp_info.max_blocks - mq->msg_count);
  547. }
  548. /// Reset a Message Queue to initial empty state.
  549. /// \note API identical to osMessageQueueReset
  550. static osStatus_t svcRtxMessageQueueReset (osMessageQueueId_t mq_id) {
  551. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  552. os_message_t *msg;
  553. os_thread_t *thread;
  554. const uint32_t *reg;
  555. const void *ptr;
  556. // Check parameters
  557. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  558. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  559. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  560. return osErrorParameter;
  561. }
  562. // Remove Messages from Queue
  563. for (;;) {
  564. // Get Message from Queue
  565. msg = MessageQueueGet(mq);
  566. if (msg == NULL) {
  567. break;
  568. }
  569. MessageQueueRemove(mq, msg);
  570. EvrRtxMessageQueueRetrieved(mq, NULL);
  571. // Free memory
  572. msg->id = osRtxIdInvalid;
  573. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  574. }
  575. // Check if Threads are waiting to send Messages
  576. if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessagePut)) {
  577. do {
  578. // Try to allocate memory
  579. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  580. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  581. if (msg != NULL) {
  582. // Wakeup waiting Thread with highest Priority
  583. thread = osRtxThreadListGet(osRtxObject(mq));
  584. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  585. // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  586. reg = osRtxThreadRegPtr(thread);
  587. //lint -e{923} "cast from unsigned int to pointer"
  588. ptr = (const void *)reg[2];
  589. memcpy(&msg[1], ptr, mq->msg_size);
  590. // Store Message into Queue
  591. msg->id = osRtxIdMessage;
  592. msg->flags = 0U;
  593. msg->priority = (uint8_t)reg[3];
  594. MessageQueuePut(mq, msg);
  595. EvrRtxMessageQueueInserted(mq, ptr);
  596. }
  597. } while ((msg != NULL) && (mq->thread_list != NULL));
  598. osRtxThreadDispatch(NULL);
  599. }
  600. EvrRtxMessageQueueResetDone(mq);
  601. return osOK;
  602. }
  603. /// Delete a Message Queue object.
  604. /// \note API identical to osMessageQueueDelete
  605. static osStatus_t svcRtxMessageQueueDelete (osMessageQueueId_t mq_id) {
  606. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  607. os_thread_t *thread;
  608. // Check parameters
  609. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  610. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  611. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  612. return osErrorParameter;
  613. }
  614. // Unblock waiting threads
  615. if (mq->thread_list != NULL) {
  616. do {
  617. thread = osRtxThreadListGet(osRtxObject(mq));
  618. osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
  619. } while (mq->thread_list != NULL);
  620. osRtxThreadDispatch(NULL);
  621. }
  622. // Mark object as invalid
  623. mq->id = osRtxIdInvalid;
  624. // Free data memory
  625. if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
  626. (void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
  627. }
  628. // Free object memory
  629. if ((mq->flags & osRtxFlagSystemObject) != 0U) {
  630. if (osRtxInfo.mpi.message_queue != NULL) {
  631. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
  632. } else {
  633. (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
  634. }
  635. #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
  636. osRtxMessageQueueMemUsage.cnt_free++;
  637. #endif
  638. }
  639. EvrRtxMessageQueueDestroyed(mq);
  640. return osOK;
  641. }
  642. // Service Calls definitions
  643. //lint ++flb "Library Begin" [MISRA Note 11]
  644. SVC0_3(MessageQueueNew, osMessageQueueId_t, uint32_t, uint32_t, const osMessageQueueAttr_t *)
  645. SVC0_1(MessageQueueGetName, const char *, osMessageQueueId_t)
  646. SVC0_4(MessageQueuePut, osStatus_t, osMessageQueueId_t, const void *, uint8_t, uint32_t)
  647. SVC0_4(MessageQueueGet, osStatus_t, osMessageQueueId_t, void *, uint8_t *, uint32_t)
  648. SVC0_1(MessageQueueGetCapacity, uint32_t, osMessageQueueId_t)
  649. SVC0_1(MessageQueueGetMsgSize, uint32_t, osMessageQueueId_t)
  650. SVC0_1(MessageQueueGetCount, uint32_t, osMessageQueueId_t)
  651. SVC0_1(MessageQueueGetSpace, uint32_t, osMessageQueueId_t)
  652. SVC0_1(MessageQueueReset, osStatus_t, osMessageQueueId_t)
  653. SVC0_1(MessageQueueDelete, osStatus_t, osMessageQueueId_t)
  654. //lint --flb "Library End"
  655. // ==== ISR Calls ====
  656. /// Put a Message into a Queue or timeout if Queue is full.
  657. /// \note API identical to osMessageQueuePut
  658. __STATIC_INLINE
  659. osStatus_t isrRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  660. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  661. os_message_t *msg;
  662. osStatus_t status;
  663. // Check parameters
  664. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
  665. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  666. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  667. return osErrorParameter;
  668. }
  669. // Try to allocate memory
  670. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  671. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  672. if (msg != NULL) {
  673. // Copy Message
  674. memcpy(&msg[1], msg_ptr, mq->msg_size);
  675. msg->id = osRtxIdMessage;
  676. msg->flags = 0U;
  677. msg->priority = msg_prio;
  678. // Register post ISR processing
  679. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  680. *((const void **)(void *)&msg->prev) = msg_ptr;
  681. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  682. *( (void **) &msg->next) = mq;
  683. osRtxPostProcess(osRtxObject(msg));
  684. EvrRtxMessageQueueInsertPending(mq, msg_ptr);
  685. status = osOK;
  686. } else {
  687. // No memory available
  688. EvrRtxMessageQueueNotInserted(mq, msg_ptr);
  689. status = osErrorResource;
  690. }
  691. return status;
  692. }
  693. /// Get a Message from a Queue or timeout if Queue is empty.
  694. /// \note API identical to osMessageQueueGet
  695. __STATIC_INLINE
  696. osStatus_t isrRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  697. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  698. os_message_t *msg;
  699. osStatus_t status;
  700. // Check parameters
  701. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
  702. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  703. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  704. return osErrorParameter;
  705. }
  706. // Get Message from Queue
  707. msg = MessageQueueGet(mq);
  708. if (msg != NULL) {
  709. // Copy Message
  710. memcpy(msg_ptr, &msg[1], mq->msg_size);
  711. if (msg_prio != NULL) {
  712. *msg_prio = msg->priority;
  713. }
  714. // Register post ISR processing
  715. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  716. *((os_message_queue_t **)(void *)&msg[1]) = mq;
  717. osRtxPostProcess(osRtxObject(msg));
  718. EvrRtxMessageQueueRetrieved(mq, msg_ptr);
  719. status = osOK;
  720. } else {
  721. // No Message available
  722. EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
  723. status = osErrorResource;
  724. }
  725. return status;
  726. }
  727. // ==== Public API ====
  728. /// Create and Initialize a Message Queue object.
  729. osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
  730. osMessageQueueId_t mq_id;
  731. EvrRtxMessageQueueNew(msg_count, msg_size, attr);
  732. if (IsIrqMode() || IsIrqMasked()) {
  733. EvrRtxMessageQueueError(NULL, (int32_t)osErrorISR);
  734. mq_id = NULL;
  735. } else {
  736. mq_id = __svcMessageQueueNew(msg_count, msg_size, attr);
  737. }
  738. return mq_id;
  739. }
  740. /// Get name of a Message Queue object.
  741. const char *osMessageQueueGetName (osMessageQueueId_t mq_id) {
  742. const char *name;
  743. if (IsIrqMode() || IsIrqMasked()) {
  744. EvrRtxMessageQueueGetName(mq_id, NULL);
  745. name = NULL;
  746. } else {
  747. name = __svcMessageQueueGetName(mq_id);
  748. }
  749. return name;
  750. }
  751. /// Put a Message into a Queue or timeout if Queue is full.
  752. osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  753. osStatus_t status;
  754. EvrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  755. if (IsIrqMode() || IsIrqMasked()) {
  756. status = isrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  757. } else {
  758. status = __svcMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  759. }
  760. return status;
  761. }
  762. /// Get a Message from a Queue or timeout if Queue is empty.
  763. osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  764. osStatus_t status;
  765. EvrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  766. if (IsIrqMode() || IsIrqMasked()) {
  767. status = isrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  768. } else {
  769. status = __svcMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  770. }
  771. return status;
  772. }
  773. /// Get maximum number of messages in a Message Queue.
  774. uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
  775. uint32_t capacity;
  776. if (IsIrqMode() || IsIrqMasked()) {
  777. capacity = svcRtxMessageQueueGetCapacity(mq_id);
  778. } else {
  779. capacity = __svcMessageQueueGetCapacity(mq_id);
  780. }
  781. return capacity;
  782. }
  783. /// Get maximum message size in a Memory Pool.
  784. uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
  785. uint32_t msg_size;
  786. if (IsIrqMode() || IsIrqMasked()) {
  787. msg_size = svcRtxMessageQueueGetMsgSize(mq_id);
  788. } else {
  789. msg_size = __svcMessageQueueGetMsgSize(mq_id);
  790. }
  791. return msg_size;
  792. }
  793. /// Get number of queued messages in a Message Queue.
  794. uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
  795. uint32_t count;
  796. if (IsIrqMode() || IsIrqMasked()) {
  797. count = svcRtxMessageQueueGetCount(mq_id);
  798. } else {
  799. count = __svcMessageQueueGetCount(mq_id);
  800. }
  801. return count;
  802. }
  803. /// Get number of available slots for messages in a Message Queue.
  804. uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
  805. uint32_t space;
  806. if (IsIrqMode() || IsIrqMasked()) {
  807. space = svcRtxMessageQueueGetSpace(mq_id);
  808. } else {
  809. space = __svcMessageQueueGetSpace(mq_id);
  810. }
  811. return space;
  812. }
  813. /// Reset a Message Queue to initial empty state.
  814. osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
  815. osStatus_t status;
  816. EvrRtxMessageQueueReset(mq_id);
  817. if (IsIrqMode() || IsIrqMasked()) {
  818. EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
  819. status = osErrorISR;
  820. } else {
  821. status = __svcMessageQueueReset(mq_id);
  822. }
  823. return status;
  824. }
  825. /// Delete a Message Queue object.
  826. osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
  827. osStatus_t status;
  828. EvrRtxMessageQueueDelete(mq_id);
  829. if (IsIrqMode() || IsIrqMasked()) {
  830. EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
  831. status = osErrorISR;
  832. } else {
  833. status = __svcMessageQueueDelete(mq_id);
  834. }
  835. return status;
  836. }