rtx_msgqueue.c 28 KB

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