rtx_msgqueue.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  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 (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. (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[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. (void)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. ((__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 (R2: void *msg_ptr, R3: uint8_t *msg_prio)
  366. reg = osRtxThreadRegPtr(thread);
  367. //lint -e{923} "cast from unsigned int to pointer"
  368. ptr = (void *)reg[2];
  369. (void)memcpy(ptr, msg_ptr, mq->msg_size);
  370. if (reg[3] != 0U) {
  371. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  372. *((uint8_t *)reg[3]) = 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. // Save arguments (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  398. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  399. reg = (uint32_t *)(__get_PSP());
  400. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  401. reg[2] = (uint32_t)msg_ptr;
  402. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  403. reg[3] = (uint32_t)msg_prio;
  404. } else {
  405. EvrRtxMessageQueuePutTimeout(mq);
  406. }
  407. status = osErrorTimeout;
  408. } else {
  409. EvrRtxMessageQueueNotInserted(mq, msg_ptr);
  410. status = osErrorResource;
  411. }
  412. }
  413. }
  414. return status;
  415. }
  416. /// Get a Message from a Queue or timeout if Queue is empty.
  417. /// \note API identical to osMessageQueueGet
  418. static osStatus_t svcRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  419. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  420. os_message_t *msg;
  421. os_thread_t *thread;
  422. uint32_t *reg;
  423. const void *ptr;
  424. osStatus_t status;
  425. // Check parameters
  426. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
  427. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  428. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  429. return osErrorParameter;
  430. }
  431. // Get Message from Queue
  432. msg = MessageQueueGet(mq);
  433. if (msg != NULL) {
  434. MessageQueueRemove(mq, msg);
  435. // Copy Message
  436. (void)memcpy(msg_ptr, &msg[1], mq->msg_size);
  437. if (msg_prio != NULL) {
  438. *msg_prio = msg->priority;
  439. }
  440. EvrRtxMessageQueueRetrieved(mq, msg_ptr);
  441. // Free memory
  442. msg->id = osRtxIdInvalid;
  443. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  444. // Check if Thread is waiting to send a Message
  445. if (mq->thread_list != NULL) {
  446. // Try to allocate memory
  447. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  448. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  449. if (msg != NULL) {
  450. // Wakeup waiting Thread with highest Priority
  451. thread = osRtxThreadListGet(osRtxObject(mq));
  452. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  453. // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  454. reg = osRtxThreadRegPtr(thread);
  455. //lint -e{923} "cast from unsigned int to pointer"
  456. ptr = (const void *)reg[2];
  457. (void)memcpy(&msg[1], ptr, mq->msg_size);
  458. // Store Message into Queue
  459. msg->id = osRtxIdMessage;
  460. msg->flags = 0U;
  461. msg->priority = (uint8_t)reg[3];
  462. MessageQueuePut(mq, msg);
  463. EvrRtxMessageQueueInserted(mq, ptr);
  464. }
  465. }
  466. status = osOK;
  467. } else {
  468. // No Message available
  469. if (timeout != 0U) {
  470. EvrRtxMessageQueueGetPending(mq, msg_ptr, timeout);
  471. // Suspend current Thread
  472. if (osRtxThreadWaitEnter(osRtxThreadWaitingMessageGet, timeout)) {
  473. osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
  474. // Save arguments (R2: void *msg_ptr, R3: uint8_t *msg_prio)
  475. //lint -e{923} -e{9078} "cast from unsigned int to pointer"
  476. reg = (uint32_t *)(__get_PSP());
  477. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  478. reg[2] = (uint32_t)msg_ptr;
  479. //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  480. reg[3] = (uint32_t)msg_prio;
  481. } else {
  482. EvrRtxMessageQueueGetTimeout(mq);
  483. }
  484. status = osErrorTimeout;
  485. } else {
  486. EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
  487. status = osErrorResource;
  488. }
  489. }
  490. return status;
  491. }
  492. /// Get maximum number of messages in a Message Queue.
  493. /// \note API identical to osMessageQueueGetCapacity
  494. static uint32_t svcRtxMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
  495. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  496. // Check parameters
  497. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  498. EvrRtxMessageQueueGetCapacity(mq, 0U);
  499. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  500. return 0U;
  501. }
  502. EvrRtxMessageQueueGetCapacity(mq, mq->mp_info.max_blocks);
  503. return mq->mp_info.max_blocks;
  504. }
  505. /// Get maximum message size in a Memory Pool.
  506. /// \note API identical to osMessageQueueGetMsgSize
  507. static uint32_t svcRtxMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
  508. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  509. // Check parameters
  510. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  511. EvrRtxMessageQueueGetMsgSize(mq, 0U);
  512. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  513. return 0U;
  514. }
  515. EvrRtxMessageQueueGetMsgSize(mq, mq->msg_size);
  516. return mq->msg_size;
  517. }
  518. /// Get number of queued messages in a Message Queue.
  519. /// \note API identical to osMessageQueueGetCount
  520. static uint32_t svcRtxMessageQueueGetCount (osMessageQueueId_t mq_id) {
  521. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  522. // Check parameters
  523. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  524. EvrRtxMessageQueueGetCount(mq, 0U);
  525. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  526. return 0U;
  527. }
  528. EvrRtxMessageQueueGetCount(mq, mq->msg_count);
  529. return mq->msg_count;
  530. }
  531. /// Get number of available slots for messages in a Message Queue.
  532. /// \note API identical to osMessageQueueGetSpace
  533. static uint32_t svcRtxMessageQueueGetSpace (osMessageQueueId_t mq_id) {
  534. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  535. // Check parameters
  536. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  537. EvrRtxMessageQueueGetSpace(mq, 0U);
  538. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  539. return 0U;
  540. }
  541. EvrRtxMessageQueueGetSpace(mq, mq->mp_info.max_blocks - mq->msg_count);
  542. return (mq->mp_info.max_blocks - mq->msg_count);
  543. }
  544. /// Reset a Message Queue to initial empty state.
  545. /// \note API identical to osMessageQueueReset
  546. static osStatus_t svcRtxMessageQueueReset (osMessageQueueId_t mq_id) {
  547. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  548. os_message_t *msg;
  549. os_thread_t *thread;
  550. const uint32_t *reg;
  551. const void *ptr;
  552. // Check parameters
  553. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  554. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  555. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  556. return osErrorParameter;
  557. }
  558. // Remove Messages from Queue
  559. for (;;) {
  560. // Get Message from Queue
  561. msg = MessageQueueGet(mq);
  562. if (msg == NULL) {
  563. break;
  564. }
  565. MessageQueueRemove(mq, msg);
  566. EvrRtxMessageQueueRetrieved(mq, NULL);
  567. // Free memory
  568. msg->id = osRtxIdInvalid;
  569. (void)osRtxMemoryPoolFree(&mq->mp_info, msg);
  570. }
  571. // Check if Threads are waiting to send Messages
  572. if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessagePut)) {
  573. do {
  574. // Try to allocate memory
  575. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  576. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  577. if (msg != NULL) {
  578. // Wakeup waiting Thread with highest Priority
  579. thread = osRtxThreadListGet(osRtxObject(mq));
  580. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  581. // Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
  582. reg = osRtxThreadRegPtr(thread);
  583. //lint -e{923} "cast from unsigned int to pointer"
  584. ptr = (const void *)reg[2];
  585. (void)memcpy(&msg[1], ptr, mq->msg_size);
  586. // Store Message into Queue
  587. msg->id = osRtxIdMessage;
  588. msg->flags = 0U;
  589. msg->priority = (uint8_t)reg[3];
  590. MessageQueuePut(mq, msg);
  591. EvrRtxMessageQueueInserted(mq, ptr);
  592. }
  593. } while ((msg != NULL) && (mq->thread_list != NULL));
  594. osRtxThreadDispatch(NULL);
  595. }
  596. EvrRtxMessageQueueResetDone(mq);
  597. return osOK;
  598. }
  599. /// Delete a Message Queue object.
  600. /// \note API identical to osMessageQueueDelete
  601. static osStatus_t svcRtxMessageQueueDelete (osMessageQueueId_t mq_id) {
  602. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  603. os_thread_t *thread;
  604. // Check parameters
  605. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
  606. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  607. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  608. return osErrorParameter;
  609. }
  610. // Unblock waiting threads
  611. if (mq->thread_list != NULL) {
  612. do {
  613. thread = osRtxThreadListGet(osRtxObject(mq));
  614. osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
  615. } while (mq->thread_list != NULL);
  616. osRtxThreadDispatch(NULL);
  617. }
  618. // Mark object as invalid
  619. mq->id = osRtxIdInvalid;
  620. // Free data memory
  621. if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
  622. (void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
  623. }
  624. // Free object memory
  625. if ((mq->flags & osRtxFlagSystemObject) != 0U) {
  626. if (osRtxInfo.mpi.message_queue != NULL) {
  627. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
  628. } else {
  629. (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
  630. }
  631. #ifdef RTX_OBJ_MEM_USAGE
  632. osRtxMessageQueueMemUsage.cnt_free++;
  633. #endif
  634. }
  635. EvrRtxMessageQueueDestroyed(mq);
  636. return osOK;
  637. }
  638. // Service Calls definitions
  639. //lint ++flb "Library Begin" [MISRA Note 11]
  640. SVC0_3(MessageQueueNew, osMessageQueueId_t, uint32_t, uint32_t, const osMessageQueueAttr_t *)
  641. SVC0_1(MessageQueueGetName, const char *, osMessageQueueId_t)
  642. SVC0_4(MessageQueuePut, osStatus_t, osMessageQueueId_t, const void *, uint8_t, uint32_t)
  643. SVC0_4(MessageQueueGet, osStatus_t, osMessageQueueId_t, void *, uint8_t *, uint32_t)
  644. SVC0_1(MessageQueueGetCapacity, uint32_t, osMessageQueueId_t)
  645. SVC0_1(MessageQueueGetMsgSize, uint32_t, osMessageQueueId_t)
  646. SVC0_1(MessageQueueGetCount, uint32_t, osMessageQueueId_t)
  647. SVC0_1(MessageQueueGetSpace, uint32_t, osMessageQueueId_t)
  648. SVC0_1(MessageQueueReset, osStatus_t, osMessageQueueId_t)
  649. SVC0_1(MessageQueueDelete, osStatus_t, osMessageQueueId_t)
  650. //lint --flb "Library End"
  651. // ==== ISR Calls ====
  652. /// Put a Message into a Queue or timeout if Queue is full.
  653. /// \note API identical to osMessageQueuePut
  654. __STATIC_INLINE
  655. osStatus_t isrRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  656. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  657. os_message_t *msg;
  658. osStatus_t status;
  659. // Check parameters
  660. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
  661. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  662. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  663. return osErrorParameter;
  664. }
  665. // Try to allocate memory
  666. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  667. msg = osRtxMemoryPoolAlloc(&mq->mp_info);
  668. if (msg != NULL) {
  669. // Copy Message
  670. (void)memcpy(&msg[1], msg_ptr, mq->msg_size);
  671. msg->id = osRtxIdMessage;
  672. msg->flags = 0U;
  673. msg->priority = msg_prio;
  674. // Register post ISR processing
  675. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  676. *((const void **)(void *)&msg->prev) = msg_ptr;
  677. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  678. *( (void **) &msg->next) = mq;
  679. osRtxPostProcess(osRtxObject(msg));
  680. EvrRtxMessageQueueInsertPending(mq, msg_ptr);
  681. status = osOK;
  682. } else {
  683. // No memory available
  684. EvrRtxMessageQueueNotInserted(mq, msg_ptr);
  685. status = osErrorResource;
  686. }
  687. return status;
  688. }
  689. /// Get a Message from a Queue or timeout if Queue is empty.
  690. /// \note API identical to osMessageQueueGet
  691. __STATIC_INLINE
  692. osStatus_t isrRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  693. os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
  694. os_message_t *msg;
  695. osStatus_t status;
  696. // Check parameters
  697. if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
  698. EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
  699. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  700. return osErrorParameter;
  701. }
  702. // Get Message from Queue
  703. msg = MessageQueueGet(mq);
  704. if (msg != NULL) {
  705. // Copy Message
  706. memcpy(msg_ptr, &msg[1], mq->msg_size);
  707. if (msg_prio != NULL) {
  708. *msg_prio = msg->priority;
  709. }
  710. // Register post ISR processing
  711. //lint -e{9079} -e{9087} "cast between pointers to different object types"
  712. *((os_message_queue_t **)(void *)&msg[1]) = mq;
  713. osRtxPostProcess(osRtxObject(msg));
  714. EvrRtxMessageQueueRetrieved(mq, msg_ptr);
  715. status = osOK;
  716. } else {
  717. // No Message available
  718. EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
  719. status = osErrorResource;
  720. }
  721. return status;
  722. }
  723. // ==== Library functions ====
  724. /// Create a Message Queue for the Timer Thread.
  725. int32_t osRtxMessageQueueTimerSetup (void) {
  726. int32_t ret = -1;
  727. osRtxInfo.timer.mq = osRtxMessageQueueId(
  728. svcRtxMessageQueueNew(osRtxConfig.timer_mq_mcnt, sizeof(os_timer_finfo_t), osRtxConfig.timer_mq_attr)
  729. );
  730. if (osRtxInfo.timer.mq != NULL) {
  731. ret = 0;
  732. }
  733. return ret;
  734. }
  735. // ==== Public API ====
  736. /// Create and Initialize a Message Queue object.
  737. osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
  738. osMessageQueueId_t mq_id;
  739. EvrRtxMessageQueueNew(msg_count, msg_size, attr);
  740. if (IsException() || IsIrqMasked()) {
  741. EvrRtxMessageQueueError(NULL, (int32_t)osErrorISR);
  742. mq_id = NULL;
  743. } else {
  744. mq_id = __svcMessageQueueNew(msg_count, msg_size, attr);
  745. }
  746. return mq_id;
  747. }
  748. /// Get name of a Message Queue object.
  749. const char *osMessageQueueGetName (osMessageQueueId_t mq_id) {
  750. const char *name;
  751. if (IsException() || IsIrqMasked()) {
  752. EvrRtxMessageQueueGetName(mq_id, NULL);
  753. name = NULL;
  754. } else {
  755. name = __svcMessageQueueGetName(mq_id);
  756. }
  757. return name;
  758. }
  759. /// Put a Message into a Queue or timeout if Queue is full.
  760. osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  761. osStatus_t status;
  762. EvrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  763. if (IsException() || IsIrqMasked()) {
  764. status = isrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  765. } else {
  766. status = __svcMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  767. }
  768. return status;
  769. }
  770. /// Get a Message from a Queue or timeout if Queue is empty.
  771. osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  772. osStatus_t status;
  773. EvrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  774. if (IsException() || IsIrqMasked()) {
  775. status = isrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  776. } else {
  777. status = __svcMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  778. }
  779. return status;
  780. }
  781. /// Get maximum number of messages in a Message Queue.
  782. uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
  783. uint32_t capacity;
  784. if (IsException() || IsIrqMasked()) {
  785. capacity = svcRtxMessageQueueGetCapacity(mq_id);
  786. } else {
  787. capacity = __svcMessageQueueGetCapacity(mq_id);
  788. }
  789. return capacity;
  790. }
  791. /// Get maximum message size in a Memory Pool.
  792. uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
  793. uint32_t msg_size;
  794. if (IsException() || IsIrqMasked()) {
  795. msg_size = svcRtxMessageQueueGetMsgSize(mq_id);
  796. } else {
  797. msg_size = __svcMessageQueueGetMsgSize(mq_id);
  798. }
  799. return msg_size;
  800. }
  801. /// Get number of queued messages in a Message Queue.
  802. uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
  803. uint32_t count;
  804. if (IsException() || IsIrqMasked()) {
  805. count = svcRtxMessageQueueGetCount(mq_id);
  806. } else {
  807. count = __svcMessageQueueGetCount(mq_id);
  808. }
  809. return count;
  810. }
  811. /// Get number of available slots for messages in a Message Queue.
  812. uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
  813. uint32_t space;
  814. if (IsException() || IsIrqMasked()) {
  815. space = svcRtxMessageQueueGetSpace(mq_id);
  816. } else {
  817. space = __svcMessageQueueGetSpace(mq_id);
  818. }
  819. return space;
  820. }
  821. /// Reset a Message Queue to initial empty state.
  822. osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
  823. osStatus_t status;
  824. EvrRtxMessageQueueReset(mq_id);
  825. if (IsException() || IsIrqMasked()) {
  826. EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
  827. status = osErrorISR;
  828. } else {
  829. status = __svcMessageQueueReset(mq_id);
  830. }
  831. return status;
  832. }
  833. /// Delete a Message Queue object.
  834. osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
  835. osStatus_t status;
  836. EvrRtxMessageQueueDelete(mq_id);
  837. if (IsException() || IsIrqMasked()) {
  838. EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
  839. status = osErrorISR;
  840. } else {
  841. status = __svcMessageQueueDelete(mq_id);
  842. }
  843. return status;
  844. }