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: msg.c,v $
00038  * Revision 1.5  2006/10/08 16:48:22  haraldkipp
00039  * Documentation fixed
00040  *
00041  * Revision 1.4  2005/01/21 16:49:44  freckle
00042  * Seperated calls to NutEventPostAsync between Threads and IRQs
00043  *
00044  * Revision 1.3  2005/01/19 17:59:46  freckle
00045  * Improved interrupt performance by reducing some critical section
00046  *
00047  * Revision 1.2  2004/03/16 16:48:45  haraldkipp
00048  * Added Jan Dubiec's H8/300 port.
00049  *
00050  * Revision 1.1  2004/02/04 18:05:07  drsung
00051  * First version of message queueing  implemented. Thanks to Ralph Mason, who provided this code.
00052  * Still contains some debug functions.
00053  *
00054  */
00055  
00056 #include <sys/heap.h>
00057 #include <sys/event.h>
00058 #include <sys/atom.h>
00059 #include <sys/thread.h>
00060 #include <sys/msg.h>
00061 #include <stddef.h> /* NULL definition */
00062 
00063 
00064 #define ASSERT(x)
00065 
00066 struct _NUTMSGTMR {
00067     NUTMSGQ *mt_que;
00068     int mt_param;
00069     void *mt_data;
00070     HANDLE mt_handle;
00071     NUTMSGTMR *mt_next;
00072     u_char mt_flags;
00073 };
00074 
00079 
00083 NUTMSGQ *nutMsgQue;
00084 
00085 NUTMSGTMR *nutMsgFreeTimers;
00086 
00096 NUTMSGQ *NutMsgQCreate(u_char bits)
00097 {
00098 
00099     NUTMSGQ *que;
00100     u_char len = 1 << bits;
00101 
00102     ASSERT(bits < 7);
00103     ASSERT(bits > 0);
00104 
00105     que = (NUTMSGQ *) (NutHeapAllocClear(sizeof(NUTMSGQ) + (sizeof(NUTMSG) * (len))));
00106 
00107     if (!que)
00108         return que;
00109 
00110     que->mq_mask = len - 1;
00111 
00112     /*Link into the Global list */
00113     que->mq_next = nutMsgQue;
00114     nutMsgQue = que;
00115 
00116     return que;
00117 }
00118 
00129 int NutMsgQBroadcast(u_char id, int param, void *data)
00130 {
00131 
00132     NUTMSGQ *pCur = nutMsgQue;
00133     int ret = 0;
00134 
00135     while (pCur) {
00136         ret -= NutMsgQPost(pCur, id, param, data);
00137         pCur = pCur->mq_next;
00138     }
00139 
00140     return ret;
00141 }
00142 
00154 int NutMsgQPost(NUTMSGQ * que, u_char id, int param, void *data)
00155 {
00156     NUTMSG *cur;
00157     NutEnterCritical();
00158 
00159     if (NutMsgQFull(que)) {
00160         NutJumpOutCritical();
00161         return -1;
00162     }
00163 
00164     cur = que->mq_que + que->mq_write;
00165 
00166     cur->id = id;
00167     cur->param = param;
00168     cur->data = data;
00169 
00170     que->mq_write++;
00171     que->mq_write &= que->mq_mask;
00172 
00173     NutExitCritical();
00174 
00175     NutEventPostAsync(&que->mq_wait);
00176     
00177     return 0;
00178 }
00179 
00194 int NutMsgQSend(NUTMSGQ * que, u_char id, int param, void *data)
00195 {
00196     if (NutMsgQPost(que, id, param, data) == 0) {
00197         NutThreadYield();
00198         return 0;
00199     }
00200     return -1;
00201 }
00202 
00208 int NutMsgQFull(NUTMSGQ * que)
00209 {
00210     if (((que->mq_write + 1) & que->mq_mask) == que->mq_read) {
00211         return -1;
00212     }
00213     return 0;
00214 }
00215 
00216 
00217 static void NutMsgQTimerCb(HANDLE hndl, void *arg)
00218 {
00219     NUTMSGTMR *timer = (NUTMSGTMR *) arg;
00220 
00221     if (NutMsgQPost(timer->mt_que, MSG_TIMER, 0, timer)) {
00222         /*
00223          * If a oneshot is missed we need to restart it until
00224          * It gets into the que otherwise we can not deallocate the NUTMSGTMR
00225          * Also oneshots are important we expect it will go off
00226          */
00227         if (timer->mt_flags && TM_ONESHOT) {
00228             timer->mt_handle = NutTimerStartTicks(1, NutMsgQTimerCb, timer, TM_ONESHOT);
00229         }
00230     } else {
00231         /*We can't kill it b/c it kills it's self */
00232         if (timer->mt_flags && TM_ONESHOT)
00233             timer->mt_handle = NULL;
00234     }
00235 }
00236 
00237 
00250 HANDLE NutMsgQStartTimer(NUTMSGQ * que, u_long ms, int param, void *data, u_char flags)
00251 {
00252     NUTMSGTMR *timer = nutMsgFreeTimers;
00253 
00254     ASSERT(flags == TM_ONESHOT || flags == 0);
00255 
00256     if (timer != NULL) {
00257         nutMsgFreeTimers = timer->mt_next;
00258     } else {
00259         timer = (NUTMSGTMR *) NutHeapAlloc(sizeof(NUTMSGTMR));
00260     }
00261 
00262     timer->mt_que = que;
00263     timer->mt_data = data;
00264     timer->mt_param = param;
00265     timer->mt_flags = flags;
00266     timer->mt_handle = NutTimerStart(ms, NutMsgQTimerCb, timer, flags);
00267 
00268     timer->mt_next = que->mq_timers;
00269     que->mq_timers = timer;
00270     return (HANDLE) timer;
00271 }
00272 
00273 static void NutMsgQFreeTimer(NUTMSGQ * que, NUTMSGTMR * handle)
00274 {
00275     NUTMSGTMR *tnp = que->mq_timers;
00276     NUTMSGTMR **tnpp = &que->mq_timers;
00277 
00278     while (tnp) {
00279         if (tnp == handle) {
00280             *tnpp = tnp->mt_next;
00281             tnp->mt_next = nutMsgFreeTimers;
00282             nutMsgFreeTimers = tnp;
00283             return;
00284         }
00285         tnpp = &tnp->mt_next;
00286         tnp = tnp->mt_next;
00287     }
00288 
00289     ASSERT(0);                  /*Timer already freed */
00290 }
00291 
00302 void NutMsgQStopTimer(HANDLE timer)
00303 {
00304     NUTMSGTMR *t = (NUTMSGTMR *) timer;
00305     NUTMSGQ *que = t->mt_que;
00306 
00307     /*
00308      * We need to remove any message in the que from this timer
00309      * If you stop it you don't want a message from it
00310      */
00311     NutEnterCritical();
00312     {
00313         u_char pos = que->mq_read;
00314 
00315         while (pos != que->mq_write) {
00316             if (que->mq_que[pos].id == MSG_TIMER && que->mq_que[pos].data == t) {
00317                 que->mq_que[pos].id = MSG_NULL;
00318             }
00319 
00320             pos = (pos + 1) & que->mq_mask;
00321         }
00322     }
00323 
00324     if (t->mt_handle)
00325         NutTimerStop(t->mt_handle);
00326 
00327     NutExitCritical();
00328 
00329     NutMsgQFreeTimer(que, t);
00330 }
00331 
00342 int NutMsgQGetMessage(NUTMSGQ * que, NUTMSG * msg, u_long timeout)
00343 {
00344     NutEnterCritical();
00345 
00346     if (NutEventWait(&que->mq_wait, timeout)) {
00347         NutJumpOutCritical();
00348         return -1;
00349     }
00350     /* Are there messages in the queue */
00351     ASSERT(que->mq_read != que->mq_write);
00352 
00353     *msg = *(que->mq_que + que->mq_read);
00354 
00355     que->mq_read++;
00356     que->mq_read &= que->mq_mask;
00357 
00358     /* If more messages then we need to Post so we can get the next one */
00359     if (que->mq_read != que->mq_write)
00360         NutEventPostAsync(&que->mq_wait);
00361 
00362     NutExitCritical();
00363 
00364     if (msg->id == MSG_TIMER) {
00365         NUTMSGTMR *timer = (NUTMSGTMR *) msg->data;
00366         msg->data = timer->mt_data;
00367         msg->param = timer->mt_param;
00368 
00369         if (timer->mt_flags & TM_ONESHOT) {
00370             NutMsgQFreeTimer(que, timer);
00371         }
00372     }
00373 
00374     return 0;
00375 }
00376 
00380 void NutMsgQFlush(NUTMSGQ * que)
00381 {
00382     NutEnterCritical();
00383 
00384     que->mq_read = que->mq_write;
00385 
00386     /*
00387        // You want to flush only when you are not waitin on it 
00388        ASSERT( que->event_wait == SIGNALED || que->event_wait == 0 )
00389      */
00390 
00391     que->mq_wait = 0;
00392     NutExitCritical();
00393 }
00394 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/