rtx_msgqueue.c 27 KB

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