rtx_msgqueue.c 28 KB

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