rtx_msgqueue.c 33 KB

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