Nut/OS  4.10.3
API Reference
msg.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 by Telogis.com. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  * This code was kindly provided by Ralph Mason.
00033  *
00034  */
00035 
00036 /*
00037  * $Log$
00038  * Revision 1.6  2008/08/11 07:00:34  haraldkipp
00039  * BSD types replaced by stdint types (feature request #1282721).
00040  *
00041  * Revision 1.5  2006/10/08 16:48:22  haraldkipp
00042  * Documentation fixed
00043  *
00044  * Revision 1.4  2005/01/21 16:49:44  freckle
00045  * Seperated calls to NutEventPostAsync between Threads and IRQs
00046  *
00047  * Revision 1.3  2005/01/19 17:59:46  freckle
00048  * Improved interrupt performance by reducing some critical section
00049  *
00050  * Revision 1.2  2004/03/16 16:48:45  haraldkipp
00051  * Added Jan Dubiec's H8/300 port.
00052  *
00053  * Revision 1.1  2004/02/04 18:05:07  drsung
00054  * First version of message queueing  implemented. Thanks to Ralph Mason, who provided this code.
00055  * Still contains some debug functions.
00056  *
00057  */
00058  
00059 #include <sys/heap.h>
00060 #include <sys/event.h>
00061 #include <sys/atom.h>
00062 #include <sys/thread.h>
00063 #include <sys/msg.h>
00064 #include <stddef.h> /* NULL definition */
00065 
00066 
00067 #define ASSERT(x)
00068 
00069 struct _NUTMSGTMR {
00070     NUTMSGQ *mt_que;
00071     int mt_param;
00072     void *mt_data;
00073     HANDLE mt_handle;
00074     NUTMSGTMR *mt_next;
00075     uint8_t mt_flags;
00076 };
00077 
00082 
00086 NUTMSGQ *nutMsgQue;
00087 
00088 NUTMSGTMR *nutMsgFreeTimers;
00089 
00099 NUTMSGQ *NutMsgQCreate(uint8_t bits)
00100 {
00101 
00102     NUTMSGQ *que;
00103     uint8_t len = 1 << bits;
00104 
00105     ASSERT(bits < 7);
00106     ASSERT(bits > 0);
00107 
00108     que = (NUTMSGQ *) (NutHeapAllocClear(sizeof(NUTMSGQ) + (sizeof(NUTMSG) * (len))));
00109 
00110     if (!que)
00111         return que;
00112 
00113     que->mq_mask = len - 1;
00114 
00115     /*Link into the Global list */
00116     que->mq_next = nutMsgQue;
00117     nutMsgQue = que;
00118 
00119     return que;
00120 }
00121 
00132 int NutMsgQBroadcast(uint8_t id, int param, void *data)
00133 {
00134 
00135     NUTMSGQ *pCur = nutMsgQue;
00136     int ret = 0;
00137 
00138     while (pCur) {
00139         ret -= NutMsgQPost(pCur, id, param, data);
00140         pCur = pCur->mq_next;
00141     }
00142 
00143     return ret;
00144 }
00145 
00157 int NutMsgQPost(NUTMSGQ * que, uint8_t id, int param, void *data)
00158 {
00159     NUTMSG *cur;
00160     NutEnterCritical();
00161 
00162     if (NutMsgQFull(que)) {
00163         NutJumpOutCritical();
00164         return -1;
00165     }
00166 
00167     cur = que->mq_que + que->mq_write;
00168 
00169     cur->id = id;
00170     cur->param = param;
00171     cur->data = data;
00172 
00173     que->mq_write++;
00174     que->mq_write &= que->mq_mask;
00175 
00176     NutExitCritical();
00177 
00178     NutEventPostAsync(&que->mq_wait);
00179     
00180     return 0;
00181 }
00182 
00197 int NutMsgQSend(NUTMSGQ * que, uint8_t id, int param, void *data)
00198 {
00199     if (NutMsgQPost(que, id, param, data) == 0) {
00200         NutThreadYield();
00201         return 0;
00202     }
00203     return -1;
00204 }
00205 
00211 int NutMsgQFull(NUTMSGQ * que)
00212 {
00213     if (((que->mq_write + 1) & que->mq_mask) == que->mq_read) {
00214         return -1;
00215     }
00216     return 0;
00217 }
00218 
00219 
00220 static void NutMsgQTimerCb(HANDLE hndl, void *arg)
00221 {
00222     NUTMSGTMR *timer = (NUTMSGTMR *) arg;
00223 
00224     if (NutMsgQPost(timer->mt_que, MSG_TIMER, 0, timer)) {
00225         /*
00226          * If a oneshot is missed we need to restart it until
00227          * It gets into the que otherwise we can not deallocate the NUTMSGTMR
00228          * Also oneshots are important we expect it will go off
00229          */
00230         if (timer->mt_flags && TM_ONESHOT) {
00231             timer->mt_handle = NutTimerStartTicks(1, NutMsgQTimerCb, timer, TM_ONESHOT);
00232         }
00233     } else {
00234         /*We can't kill it b/c it kills it's self */
00235         if (timer->mt_flags && TM_ONESHOT)
00236             timer->mt_handle = NULL;
00237     }
00238 }
00239 
00240 
00253 HANDLE NutMsgQStartTimer(NUTMSGQ * que, uint32_t ms, int param, void *data, uint8_t flags)
00254 {
00255     NUTMSGTMR *timer = nutMsgFreeTimers;
00256 
00257     ASSERT(flags == TM_ONESHOT || flags == 0);
00258 
00259     if (timer != NULL) {
00260         nutMsgFreeTimers = timer->mt_next;
00261     } else {
00262         timer = (NUTMSGTMR *) NutHeapAlloc(sizeof(NUTMSGTMR));
00263     }
00264 
00265     timer->mt_que = que;
00266     timer->mt_data = data;
00267     timer->mt_param = param;
00268     timer->mt_flags = flags;
00269     timer->mt_handle = NutTimerStart(ms, NutMsgQTimerCb, timer, flags);
00270 
00271     timer->mt_next = que->mq_timers;
00272     que->mq_timers = timer;
00273     return (HANDLE) timer;
00274 }
00275 
00276 static void NutMsgQFreeTimer(NUTMSGQ * que, NUTMSGTMR * handle)
00277 {
00278     NUTMSGTMR *tnp = que->mq_timers;
00279     NUTMSGTMR **tnpp = &que->mq_timers;
00280 
00281     while (tnp) {
00282         if (tnp == handle) {
00283             *tnpp = tnp->mt_next;
00284             tnp->mt_next = nutMsgFreeTimers;
00285             nutMsgFreeTimers = tnp;
00286             return;
00287         }
00288         tnpp = &tnp->mt_next;
00289         tnp = tnp->mt_next;
00290     }
00291 
00292     ASSERT(0);                  /*Timer already freed */
00293 }
00294 
00305 void NutMsgQStopTimer(HANDLE timer)
00306 {
00307     NUTMSGTMR *t = (NUTMSGTMR *) timer;
00308     NUTMSGQ *que = t->mt_que;
00309 
00310     /*
00311      * We need to remove any message in the que from this timer
00312      * If you stop it you don't want a message from it
00313      */
00314     NutEnterCritical();
00315     {
00316         uint8_t pos = que->mq_read;
00317 
00318         while (pos != que->mq_write) {
00319             if (que->mq_que[pos].id == MSG_TIMER && que->mq_que[pos].data == t) {
00320                 que->mq_que[pos].id = MSG_NULL;
00321             }
00322 
00323             pos = (pos + 1) & que->mq_mask;
00324         }
00325     }
00326 
00327     if (t->mt_handle)
00328         NutTimerStop(t->mt_handle);
00329 
00330     NutExitCritical();
00331 
00332     NutMsgQFreeTimer(que, t);
00333 }
00334 
00345 int NutMsgQGetMessage(NUTMSGQ * que, NUTMSG * msg, uint32_t timeout)
00346 {
00347     NutEnterCritical();
00348 
00349     if (NutEventWait(&que->mq_wait, timeout)) {
00350         NutJumpOutCritical();
00351         return -1;
00352     }
00353     /* Are there messages in the queue */
00354     ASSERT(que->mq_read != que->mq_write);
00355 
00356     *msg = *(que->mq_que + que->mq_read);
00357 
00358     que->mq_read++;
00359     que->mq_read &= que->mq_mask;
00360 
00361     /* If more messages then we need to Post so we can get the next one */
00362     if (que->mq_read != que->mq_write)
00363         NutEventPostAsync(&que->mq_wait);
00364 
00365     NutExitCritical();
00366 
00367     if (msg->id == MSG_TIMER) {
00368         NUTMSGTMR *timer = (NUTMSGTMR *) msg->data;
00369         msg->data = timer->mt_data;
00370         msg->param = timer->mt_param;
00371 
00372         if (timer->mt_flags & TM_ONESHOT) {
00373             NutMsgQFreeTimer(que, timer);
00374         }
00375     }
00376 
00377     return 0;
00378 }
00379 
00383 void NutMsgQFlush(NUTMSGQ * que)
00384 {
00385     NutEnterCritical();
00386 
00387     que->mq_read = que->mq_write;
00388 
00389     /*
00390        // You want to flush only when you are not waitin on it 
00391        ASSERT( que->event_wait == SIGNALED || que->event_wait == 0 )
00392      */
00393 
00394     que->mq_wait = 0;
00395     NutExitCritical();
00396 }
00397