/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                       MESSAGE MAILBOX MANAGEMENT
*
*                        (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
*                                           All Rights Reserved
*
*                                                  V2.00
*
* File : OS_MBOX.C
* By   : Jean J. Labrosse
*********************************************************************************************************
*/

#ifndef  OS_MASTER_FILE
#include "includes.h"
#endif

#if OS_MBOX_EN
/*
*********************************************************************************************************
*                                     ´ë±â¾øÀÌ ¸ÞÀϹڽº¿¡¼­ ¸Þ½ÃÁö ¹Þ±â
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö°¡ À¯È¿ÇÑÁö Á¡°ËÇÑ´Ù. OSMboxPend()¿Í ´Ù¸¥ Á¡Àº, ¸Þ½ÃÁö°¡
*              ¾ø´Â °æ¿ì¿¡µµ OSMboxAccept()¸¦ È£ÃâÇÑ Å½ºÅ©¸¦ ´ë±â»óÅ·Π¸¸µéÁö ¾Ê´Â´Ù´Â Á¡ÀÌ´Ù
*
* Àü´ÞÀÎÀÚ   : pevent        ÇØ´ç ¸ÞÀϹڽºÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.
*
* ¸®Åϰª     : != (void *)0  ¸Þ½ÃÁö°¡ À¯È¿ÇÑ °æ¿ì ¸ÞÀϹڽº¿¡¼­ Àоî¿Â ¸Þ½ÃÁö. ¸ÞÀϹڽº´Â Ŭ¸®¾îµÇ¹Ç·Î
*                            ´ÙÀ½ ¹ø¿¡ OSMboxAccept()¸¦ È£ÃâÇÏ¸é ¸ÞÀϹڽº´Â ºñ¾îÀÖÀ» °ÍÀÌ´Ù.
*              == (void *)0  ¸ÞÀϹڽº°¡ ºñ¾î Àְųª, ºÎÀûÀýÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï Æ÷ÀÎÅ͸¦ Àü´ÞÇßÀ½.
*********************************************************************************************************
*/

void *OSMboxAccept (OS_EVENT *pevent)
{
    void  *msg;


    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {      /* À¯È¿ÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÎÁö Á¡°Ë        */
        OS_EXIT_CRITICAL();
        return ((void *)0);
    }
    msg = pevent->OSEventPtr; 
    if (msg != (void *)0) {                               /* ÀÌ¹Ì ¸Þ½ÃÁö°¡ ÀÖ´ÂÁö È®ÀÎ                 */
        pevent->OSEventPtr = (void *)0;                   /* ¸ÞÀϹڽº Ŭ¸®¾î                           */
    }
    OS_EXIT_CRITICAL();
    return (msg);                                         /* NULL ¶Ç´Â ¼ö½ÅÇÑ ¸Þ½ÃÁö¸¦ ¸®ÅÏ            */
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                          ¸Þ½ÃÁö ¸ÞÀϹڽº »ý¼º
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ºó À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÌ ÀÖÀ» °æ¿ì ¸Þ½ÃÁö ¸ÞÀϹڽº¸¦ »ý¼ºÇÑ´Ù.
*
* Àü´ÞÀÎÀÚ   : msg           ¸ÞÀϹڽº¿¡ ¼ÛºÎÇϰíÀÚ ÇÏ´Â ¸Þ½ÃÁö¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.
*                            ÀÌ °ªÀ» NULL·Î ¼³Á¤Çϸé(i.e. (void *)0) ¸ÞÀϹڽº´Â ºñ¾îÀÖ´Â
*                            °ÍÀ¸·Î °£ÁֵȴÙ.
*
* ¸®Åϰª     : != (void *)0  »ý¼ºµÈ ¸ÞÀϹڽº¿¡ ÇØ´çÇÏ´Â À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï(OS_EVENT)¿¡ ´ëÇÑ Æ÷ÀÎÅÍ
*
*              == (void *)0  ÇÒ´çÇÒ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÌ ¾øÀ½.
*********************************************************************************************************
*/

OS_EVENT *OSMboxCreate (void *msg)
{
    OS_EVENT *pevent;


    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                    /* ºó À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» ¾ò´Â´Ù                     */
    if (OSEventFreeList != (OS_EVENT *)0) {      /* ¾òÀº À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÌ À¯È¿ÇÑÁö È®ÀÎ            */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {
        pevent->OSEventType = OS_EVENT_TYPE_MBOX;
        pevent->OSEventPtr  = msg;               /* À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï¿¡ ¸Þ½ÃÁö¸¦ ¼ÛºÎ                 */
        OSEventWaitListInit(pevent);
    }
    return (pevent);                             /* À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï¿¡ ´ëÇÑ Æ÷ÀÎÅ͸¦ ¸®ÅÏ            */
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                  ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö°¡ µµÂøÇÒ ¶§±îÁö ´ë±â
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö°¡ µµÂøÇÒ ¶§¸¦ ±â´Ù¸°´Ù
*
* Àü´ÞÀÎÀÚ   : pevent        ÇØ´ç ¸ÞÀϹڽºÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.
*
*              timeout       ¿É¼Ç ŸÀӾƿô °ª(Ŭ·° ƽ ´ÜÀ§). ÀÌ °ªÀÌ 0ÀÌ ¾Æ´Ñ °æ¿ì, ŽºÅ©´Â ÁöÁ¤ÇÑ ½Ã°£
*                            µ¿¾È ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö°¡ µµÂøÇϱ⸦ ±â´Ù¸°´Ù.
*                            ±×·¯³ª ÀÌ °ª¿¡ 0À» ÁöÁ¤ÇÑ °æ¿ì, ¸Þ½ÃÁö°¡ µµÂøÇÒ ¶§±îÁö ¿µ¿øÈ÷ ´ë±â»óÅ·Î
*                            ³²¾Æ Àִ´Ù.
*
*              err           ¿¡·¯Äڵ带 ÀúÀåÇÒ ¸Þ¸ð¸®¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*                            °¡´ÉÇÑ ¿¡·¯ÄÚµå´Â ´ÙÀ½°ú °°´Ù.
*
*                            OS_NO_ERR         È£ÃâÀÌ ¼º°øÇßÀ¸¸ç, ¸Þ½ÃÁö¸¦ ¹Þ¾ÒÀ½.
*                            OS_TIMEOUT        ÁöÁ¤ÇÑ Å¸ÀӾƿôµ¿¾È ¸Þ½ÃÁö¸¦ ¹ÞÁö ¸øÇßÀ½.
*                            OS_ERR_EVENT_TYPE ¹«È¿ÇÑ À̺¥Æ® ŸÀÔÀ» ÁöÁ¤ÇßÀ½.
*                            OS_ERR_PEND_ISR   ÀÌ ÇÔ¼ö¸¦ ISR¿¡¼­ È£ÃâÇßÀ½.
*                                              ISRÀº ´ë±â»óŰ¡ µÉ ¼ö ¾øÀ¸¹Ç·Î ¹Ù·Î ¸®ÅÏÇßÀ½.
*
* ¸®Åϰª     : != (void *)0  ¼ö½ÅµÈ ¸Þ½ÃÁö¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.
*              == (void *)0  ¸Þ½ÃÁö°¡ µµÂøÇÏÁö ¾Ê¾Ò°Å³ª, ºÎÀûÀýÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» ÁöÁ¤ÇßÀ½.
*
*********************************************************************************************************
*/

void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
    void  *msg;


    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* À¯È¿ÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÎÁö Á¡°Ë            */
        OS_EXIT_CRITICAL();
        *err = OS_ERR_EVENT_TYPE;
        return ((void *)0);
    }
    msg = pevent->OSEventPtr;
    if (msg != (void *)0) {                           /* ÀÌ¹Ì ¸Þ½ÃÁö°¡ ÀÖ´ÂÁö È®ÀÎ                     */
        pevent->OSEventPtr = (void *)0;               /* ¸ÞÀϹڽº Ŭ¸®¾î                               */
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
    } else if (OSIntNesting > 0) {                    /* ISR¿¡¼­ È£ÃâÇß´ÂÁö È®ÀÎ...                    */
        OS_EXIT_CRITICAL();                           /* ... ISRÀº ´ë±âÇÏ¸é ¾ÈµÊ                       */
        *err = OS_ERR_PEND_ISR;
    } else {
        OSTCBCur->OSTCBStat |= OS_STAT_MBOX;          /* ¸Þ½ÃÁö°¡ ¾øÀ½, ŽºÅ©´Â ´ë±â»óŰ¡ µÊ         */
        OSTCBCur->OSTCBDly   = timeout;               /* TCB¿¡ ŸÀӾƿô °ªÀ» ÀúÀå                      */
        OSEventTaskWait(pevent);                      /* ŸÀӾƿô ¸¸·á³ª ¸Þ½ÃÁö°¡ µµÂøÇÒ ¶§±îÁö ´ë±â   */
        OS_EXIT_CRITICAL();
        OSSched();                                    /* ½ÇÇà Áغñ»óÅÂÀÎ ´ÙÀ½ ¿ì¼±¼øÀ§ ŽºÅ© °áÁ¤     */
        OS_ENTER_CRITICAL();
        if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) {     /* ¸Þ½ÃÁö°¡ ÀÖ´ÂÁö È®ÀÎ                     */
            OSTCBCur->OSTCBMsg      = (void *)0;           /* ¿¹, ¹ÞÀº ¸Þ½ÃÁö¸¦ Áö¿ò                   */
            OSTCBCur->OSTCBStat     = OS_STAT_RDY;
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;       /* ´õÀÌ»ó À̺¥Æ®¸¦ ±â´Ù¸®Áö ¾ÊÀ½            */
            OS_EXIT_CRITICAL();
            *err                    = OS_NO_ERR;
        } else if (OSTCBCur->OSTCBStat & OS_STAT_MBOX) {   /* OS_STAT_RDY »óŰ¡ ¾Æ´Ï°í, ŸÀӾƿô ¹ß»ý */
            OSEventTO(pevent);                             /* ŽºÅ©¸¦ Áغñ»óÅ·Π¸¸µç´Ù               */
            OS_EXIT_CRITICAL();
            msg                     = (void *)0;           /* ¸Þ½ÃÁö ³»¿ëÀ» NULL·Î ¼³Á¤                */
            *err                    = OS_TIMEOUT;          /* ŸÀӾƿôÀÌ ¹ß»ýÇßÀ½À» ¾Ë¸²               */
        } else {
            msg                     = pevent->OSEventPtr;  /* ¸Þ½ÃÁö ¼ö½Å                              */
            pevent->OSEventPtr      = (void *)0;           /* ¸ÞÀϹڽº Áö¿ò                            */
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
            OS_EXIT_CRITICAL();
            *err                    = OS_NO_ERR;
        }
    }
    return (msg);                                          /* ¹ÞÀº ¸Þ½ÃÁö³ª NULLÀ» ¸®ÅÏÇÔ              */
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                        ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö ¼ÛºÎ
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¸ÞÀϹڽº·Î ¸Þ½ÃÁö¸¦ º¸³½´Ù.
*
* Àü´ÞÀÎÀÚ   : pevent        ÇØ´ç ¸ÞÀϹڽºÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.
*
*              msg           º¸³»·Á´Â ¸Þ½ÃÁö¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.  NULL Æ÷ÀÎÅ͸¦ º¸³»¸é ¾ÈµÈ´Ù.  
*
* ¸®Åϰª     : OS_NO_ERR          È£Ãâ¿¡ ¼º°øÇؼ­ ¸Þ½ÃÁö¸¦ º¸³ÂÀ½.
*              OS_MBOX_FULL       ¸ÞÀϹڽº¿¡ 󸮵ÇÁö ¾ÊÀº ¸Þ½ÃÁö°¡ ÀÖÀ½. ¸ÞÀϹڽº´Â Çѹø¿¡ ÇϳªÀÇ
*                                 ¸Þ½ÃÁö¸¸ ó¸®ÇÒ ¼ö ÀÖÀ¸¹Ç·Î, »õ·Î¿î ¸Þ½ÃÁö¸¦ Àü¼ÛÇϱâ Àü¿¡ ¸ÞÀϹڽº¿¡
*                                 ÀÖ´Â ¸Þ½ÃÁö´Â ¹Ýµå½Ã ±× ÀÌÀü¿¡ ó¸®µÅ¾ß ÇÑ´Ù.
*              OS_ERR_EVENT_TYPE  ¾ø´Â ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö¸¦ ¼ÛºÎÇÏ·Á ÇßÀ½.
*********************************************************************************************************
*/

INT8U OSMboxPost (OS_EVENT *pevent, void *msg)
{
    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* À¯È¿ÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÎÁö Á¡°Ë            */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
    }
    if (pevent->OSEventGrp) {                         /* ´Ù¸¥ ŽºÅ©°¡ ¸ÞÀϹڽº¿¡ ´ë±âÇϰí ÀÖ´ÂÁö È®ÀÎ */
        OSEventTaskRdy(pevent, msg, OS_STAT_MBOX);    /* °¡Àå ¿ì¼±¼øÀ§°¡ ³ôÀº ŽºÅ©¸¦ Áغñ»óÅ·ΠÇÔ   */
        OS_EXIT_CRITICAL();
        OSSched();                                    /* Áغñ»óÅÂÀÇ Å½ºÅ© Áß ÃÖ»óÀ§ ¿ì¼±¼øÀ§¸¦ °áÁ¤   */
        return (OS_NO_ERR);
    } else {
        if (pevent->OSEventPtr != (void *)0) {        /* ¸ÞÀϹڽº°¡ ºñ¾ú´ÂÁö È®ÀÎ                      */
            OS_EXIT_CRITICAL();
            return (OS_MBOX_FULL);
        } else {
            pevent->OSEventPtr = msg;                 /* ¸ÞÀϹڽº¿¡ ¸Þ½ÃÁö¸¦ ÀúÀå                      */
            OS_EXIT_CRITICAL();
            return (OS_NO_ERR);
        }
    }
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                      ¸Þ½ÃÁö ¸ÞÀϹڽºÀÇ »óÅ ¾ò±â
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¸Þ½ÃÁö ¸ÞÀϹڽº¿¡ ´ëÇÑ Á¤º¸¸¦ ¾ò¾î³½´Ù.
*
* Àü´ÞÀÎÀÚ   : pevent        ÇØ´ç ¸ÞÀϹڽºÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï¿¡ ´ëÇÑ Æ÷ÀÎÅÍ.
*
*              pdata         ¸Þ½ÃÁö ¸ÞÀϹڽº¿¡ ´ëÇÑ Á¤º¸¸¦ ÀúÀåÇÒ ±¸Á¶Ã¼¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*
*
* ¸®Åϰª     : OS_NO_ERR          È£ÃâÀÌ ¼º°øÇßÀ½.
*              OS_ERR_EVENT_TYPE  ¾ø´Â ¸ÞÀϹڽº¿¡ ´ëÇÑ Á¶È¸¸¦ ½ÃµµÇßÀ½.
*********************************************************************************************************
*/

INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata)
{
    INT8U  i;
    INT8U *psrc;
    INT8U *pdest;
    
    
    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {       /* À¯È¿ÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀÎÁö Á¡°Ë       */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
    }
    pdata->OSEventGrp = pevent->OSEventGrp;                /* ¸Þ½ÃÁö ¸ÞÀϹڽºÀÇ ´ë±â ¸®½ºÆ®¸¦ º¹»ç     */
    psrc              = &pevent->OSEventTbl[0];
    pdest             = &pdata->OSEventTbl[0];
    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
        *pdest++ = *psrc++;   
    }
    pdata->OSMsg = pevent->OSEventPtr;                     /* ¸ÞÀϹڽº¿¡¼­ ¸Þ½ÃÁö¸¦ ¾òÀ½               */
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif