msg.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * Copyright (C) 2001-2003 by Telogis.com. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. * This code was kindly provided by Ralph Mason.
  33. *
  34. */
  35. /*
  36. * $Log$
  37. * Revision 1.6 2008/08/11 07:00:34 haraldkipp
  38. * BSD types replaced by stdint types (feature request #1282721).
  39. *
  40. * Revision 1.5 2006/10/08 16:48:22 haraldkipp
  41. * Documentation fixed
  42. *
  43. * Revision 1.4 2005/01/21 16:49:44 freckle
  44. * Seperated calls to NutEventPostAsync between Threads and IRQs
  45. *
  46. * Revision 1.3 2005/01/19 17:59:46 freckle
  47. * Improved interrupt performance by reducing some critical section
  48. *
  49. * Revision 1.2 2004/03/16 16:48:45 haraldkipp
  50. * Added Jan Dubiec's H8/300 port.
  51. *
  52. * Revision 1.1 2004/02/04 18:05:07 drsung
  53. * First version of message queueing implemented. Thanks to Ralph Mason, who provided this code.
  54. * Still contains some debug functions.
  55. *
  56. */
  57. #include <sys/heap.h>
  58. #include <sys/event.h>
  59. #include <sys/atom.h>
  60. #include <sys/thread.h>
  61. #include <sys/msg.h>
  62. #include <stddef.h> /* NULL definition */
  63. #define ASSERT(x)
  64. struct _NUTMSGTMR {
  65. NUTMSGQ *mt_que;
  66. int mt_param;
  67. void *mt_data;
  68. HANDLE mt_handle;
  69. NUTMSGTMR *mt_next;
  70. uint8_t mt_flags;
  71. };
  72. /*!
  73. * \addtogroup xgMessageQue
  74. */
  75. /*@{*/
  76. /*!
  77. * \brief global list of ques
  78. */
  79. NUTMSGQ *nutMsgQue;
  80. NUTMSGTMR *nutMsgFreeTimers;
  81. /*!
  82. * \brief Allocate a new message que
  83. *
  84. * \param bits size of the que in bits
  85. *
  86. * \return Handle of the new que
  87. *
  88. * \note que size will be 2^bits
  89. */
  90. NUTMSGQ *NutMsgQCreate(uint8_t bits)
  91. {
  92. NUTMSGQ *que;
  93. uint8_t len = 1 << bits;
  94. ASSERT(bits < 7);
  95. ASSERT(bits > 0);
  96. que = (NUTMSGQ *) (NutHeapAllocClear(sizeof(NUTMSGQ) + (sizeof(NUTMSG) * (len))));
  97. if (!que)
  98. return que;
  99. que->mq_mask = len - 1;
  100. /*Link into the Global list */
  101. que->mq_next = nutMsgQue;
  102. nutMsgQue = que;
  103. return que;
  104. }
  105. /*!
  106. * \brief Send a message to all message ques
  107. *
  108. * \param id the id of the sent message
  109. * \param param the param of the sent message
  110. * \param data the data of the sent message
  111. *
  112. * \return 0 if sent to all ques, < 0 if one or more ques were full
  113. *
  114. */
  115. int NutMsgQBroadcast(uint8_t id, int param, void *data)
  116. {
  117. NUTMSGQ *pCur = nutMsgQue;
  118. int ret = 0;
  119. while (pCur) {
  120. ret -= NutMsgQPost(pCur, id, param, data);
  121. pCur = pCur->mq_next;
  122. }
  123. return ret;
  124. }
  125. /*!
  126. * \brief Send a message to a que and return immediately
  127. *
  128. * \param que the que to send to
  129. * \param id the id of the sent message
  130. * \param param the param of the sent message
  131. * \param data the data of the sent message
  132. *
  133. * \return 0 if sent, < 0 if the que is full
  134. *
  135. */
  136. int NutMsgQPost(NUTMSGQ * que, uint8_t id, int param, void *data)
  137. {
  138. NUTMSG *cur;
  139. NutEnterCritical();
  140. if (NutMsgQFull(que)) {
  141. NutJumpOutCritical();
  142. return -1;
  143. }
  144. cur = que->mq_que + que->mq_write;
  145. cur->id = id;
  146. cur->param = param;
  147. cur->data = data;
  148. que->mq_write++;
  149. que->mq_write &= que->mq_mask;
  150. NutExitCritical();
  151. NutEventPostAsync(&que->mq_wait);
  152. return 0;
  153. }
  154. /*!
  155. * \brief Send a message to a que and yields so that
  156. * a waiting thread can act on the message.
  157. *
  158. * The sending thread should have a lower priority than the receiver thread
  159. *
  160. * \param que the que to send to
  161. * \param id the id of the sent message
  162. * \param param the param of the sent message
  163. * \param data the data of the sent message
  164. *
  165. * \return 0 if sent, < 0 if the que is full
  166. *
  167. */
  168. int NutMsgQSend(NUTMSGQ * que, uint8_t id, int param, void *data)
  169. {
  170. if (NutMsgQPost(que, id, param, data) == 0) {
  171. NutThreadYield();
  172. return 0;
  173. }
  174. return -1;
  175. }
  176. /*!
  177. * \brief Checks the state of a que
  178. *
  179. * \return -1 if full
  180. */
  181. int NutMsgQFull(NUTMSGQ * que)
  182. {
  183. if (((que->mq_write + 1) & que->mq_mask) == que->mq_read) {
  184. return -1;
  185. }
  186. return 0;
  187. }
  188. static void NutMsgQTimerCb(HANDLE hndl, void *arg)
  189. {
  190. NUTMSGTMR *timer = (NUTMSGTMR *) arg;
  191. if (NutMsgQPost(timer->mt_que, MSG_TIMER, 0, timer)) {
  192. /*
  193. * If a oneshot is missed we need to restart it until
  194. * It gets into the que otherwise we can not deallocate the NUTMSGTMR
  195. * Also oneshots are important we expect it will go off
  196. */
  197. if (timer->mt_flags && TM_ONESHOT) {
  198. timer->mt_handle = NutTimerStartTicks(1, NutMsgQTimerCb, timer, TM_ONESHOT);
  199. }
  200. } else {
  201. /*We can't kill it b/c it kills it's self */
  202. if (timer->mt_flags && TM_ONESHOT)
  203. timer->mt_handle = NULL;
  204. }
  205. }
  206. /*!
  207. * \brief Starts a periodic or one-shot timer on the given que
  208. *
  209. * \param que the que to send to
  210. * \param ms timeout length of the timer
  211. * \param param the param of the sent message
  212. * \param data the data of the sent message
  213. * \param flags 0 or TM_ONESHOT
  214. *
  215. * \return HANDLE of the new timer
  216. *
  217. */
  218. HANDLE NutMsgQStartTimer(NUTMSGQ * que, uint32_t ms, int param, void *data, uint8_t flags)
  219. {
  220. NUTMSGTMR *timer = nutMsgFreeTimers;
  221. ASSERT(flags == TM_ONESHOT || flags == 0);
  222. if (timer != NULL) {
  223. nutMsgFreeTimers = timer->mt_next;
  224. } else {
  225. timer = (NUTMSGTMR *) NutHeapAlloc(sizeof(NUTMSGTMR));
  226. }
  227. timer->mt_que = que;
  228. timer->mt_data = data;
  229. timer->mt_param = param;
  230. timer->mt_flags = flags;
  231. timer->mt_handle = NutTimerStart(ms, NutMsgQTimerCb, timer, flags);
  232. timer->mt_next = que->mq_timers;
  233. que->mq_timers = timer;
  234. return (HANDLE) timer;
  235. }
  236. static void NutMsgQFreeTimer(NUTMSGQ * que, NUTMSGTMR * handle)
  237. {
  238. NUTMSGTMR *tnp = que->mq_timers;
  239. NUTMSGTMR **tnpp = &que->mq_timers;
  240. while (tnp) {
  241. if (tnp == handle) {
  242. *tnpp = tnp->mt_next;
  243. tnp->mt_next = nutMsgFreeTimers;
  244. nutMsgFreeTimers = tnp;
  245. return;
  246. }
  247. tnpp = &tnp->mt_next;
  248. tnp = tnp->mt_next;
  249. }
  250. ASSERT(0); /*Timer already freed */
  251. }
  252. /*!
  253. * \brief Stops a timer
  254. *
  255. * \param timer HANDLE of the timer to stop
  256. *
  257. * \note You must not stop a one shot that has already expired
  258. * otherwise it *could* have been reused and you will end up stopping
  259. * another timer
  260. *
  261. */
  262. void NutMsgQStopTimer(HANDLE timer)
  263. {
  264. NUTMSGTMR *t = (NUTMSGTMR *) timer;
  265. NUTMSGQ *que = t->mt_que;
  266. /*
  267. * We need to remove any message in the que from this timer
  268. * If you stop it you don't want a message from it
  269. */
  270. NutEnterCritical();
  271. {
  272. uint8_t pos = que->mq_read;
  273. while (pos != que->mq_write) {
  274. if (que->mq_que[pos].id == MSG_TIMER && que->mq_que[pos].data == t) {
  275. que->mq_que[pos].id = MSG_NULL;
  276. }
  277. pos = (pos + 1) & que->mq_mask;
  278. }
  279. }
  280. if (t->mt_handle)
  281. NutTimerStop(t->mt_handle);
  282. NutExitCritical();
  283. NutMsgQFreeTimer(que, t);
  284. }
  285. /*!
  286. * \brief Gets the next message from the que
  287. *
  288. * \param que the que to wait on
  289. * \param msg pointer to memory to return data to
  290. * \param timeout how long to wait for a message
  291. *
  292. * \return -1 on timeout, 0 if message retreived
  293. */
  294. int NutMsgQGetMessage(NUTMSGQ * que, NUTMSG * msg, uint32_t timeout)
  295. {
  296. NutEnterCritical();
  297. if (NutEventWait(&que->mq_wait, timeout)) {
  298. NutJumpOutCritical();
  299. return -1;
  300. }
  301. /* Are there messages in the queue */
  302. ASSERT(que->mq_read != que->mq_write);
  303. *msg = *(que->mq_que + que->mq_read);
  304. que->mq_read++;
  305. que->mq_read &= que->mq_mask;
  306. /* If more messages then we need to Post so we can get the next one */
  307. if (que->mq_read != que->mq_write)
  308. NutEventPostAsync(&que->mq_wait);
  309. NutExitCritical();
  310. if (msg->id == MSG_TIMER) {
  311. NUTMSGTMR *timer = (NUTMSGTMR *) msg->data;
  312. msg->data = timer->mt_data;
  313. msg->param = timer->mt_param;
  314. if (timer->mt_flags & TM_ONESHOT) {
  315. NutMsgQFreeTimer(que, timer);
  316. }
  317. }
  318. return 0;
  319. }
  320. /*!
  321. * \brief Removes all entries from a que
  322. */
  323. void NutMsgQFlush(NUTMSGQ * que)
  324. {
  325. NutEnterCritical();
  326. que->mq_read = que->mq_write;
  327. /*
  328. // You want to flush only when you are not waitin on it
  329. ASSERT( que->event_wait == SIGNALED || que->event_wait == 0 )
  330. */
  331. que->mq_wait = 0;
  332. NutExitCritical();
  333. }
  334. /*@}*/