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

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

#if OS_SEM_EN
/*
*********************************************************************************************************
*                                         ´ë±â¾øÀÌ ¼¼¸¶Æ÷¾î ¾ò±â
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ÀÚ¿øÀÌ »ç¿ë °¡´ÉÇÑÁö ¶Ç´Â À̺¥Æ®°¡ ¹ß»ýÇß´ÂÁö ¾Ë¾Æº¸±â À§ÇØ ¼¼¸¶Æ÷¾î¸¦ Á¡°ËÇÑ´Ù.
*              OSSemAccept()°¡ OSSemPend()¿Í ´Ù¸¥ Á¡Àº À̺¥Æ®°¡ ¹ß»ýÇÏÁö ¾Ê¾Ò°í, ÀÚ¿øÀÌ »ç¿ë °¡´É »óŰ¡
*              ¾Æ´Ò °æ¿ì ŽºÅ©¸¦ ´ë±â»óÅ·Π¸¸µéÁö ¾Ê´Â´Ù´Â Á¡ÀÌ´Ù.
*
* Àü´ÞÀÎÀÚ   : pevent     ÇØ´ç ¼¼¸¶Æ÷¾îÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*
* ¸®Åϰª     : >  0       ÀÚ¿øÀÌ »ç¿ë °¡´ÉÇϰųª À̺¥Æ®°¡ ¹ß»ýÇß´Ù¸é ÀÚ¿øÀ» ¾ò±âÀ§ÇØ ¼¼¸¶Æ÷¾î Ä«¿îÆ®¸¦
*                         °¨¼ÒÇÑ´Ù.
*              == 0       ÀÚ¿øÀÌ »ç¿ë°¡´ÉÇÏÁö ¾Ê°Å³ª, À̺¥Æ®°¡ ¹ß»ýÇÏÁö ¾Ê¾Ò°Å³ª, 
*                         ¼¼¸¶Æ÷¾î¸¦ °¡¸®Å°´Â Æ÷ÀÎÅ͸¦ ÁöÁ¤ÇÏÁö ¾ÊÀº °æ¿ì.
*********************************************************************************************************
*/

INT16U OSSemAccept (OS_EVENT *pevent)
{
    INT16U cnt;


    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* À̺¥Æ® ºí·Ï ŸÀÔ Á¡°Ë                         */
        OS_EXIT_CRITICAL();
        return (0);
    }
    cnt = pevent->OSEventCnt;
    if (cnt > 0) {                                    /* ÀÚ¿øÀÌ »ç¿ë °¡´ÉÇÑÁö È®ÀÎ                     */
        pevent->OSEventCnt--;                         /* ¿¹, ¼¼¸¶Æ÷¾î¸¦ °¨¼ÒÇϰí È£ÃâÀÚ¿¡°Ô ¾Ë¸°´Ù     */
    }
    OS_EXIT_CRITICAL();
    return (cnt);                                     /* ¼¼¸¶Æ÷¾î Ä«¿îÆ® ¸®ÅÏ                          */
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                              ¼¼¸¶Æ÷¾î »ý¼º
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¼¼¸¶Æ÷¾î¸¦ »ý¼ºÇÑ´Ù.
*
* Àü´ÞÀÎÀÚ   : cnt           ¼¼¸¶Æ÷¾îÀÇ ÃʱⰪ. ÀÌ °ªÀÌ 0À̸é ÀÚ¿øÀÌ »ç¿ë °¡´ÉÇÏÁö ¾ÊÀ½
*                            (¶Ç´Â À̺¥Æ®°¡ ¹ß»ýÇÏÁö ¾Ê¾ÒÀ½). ÀÚ¿øÀÌ »ç¿ë °¡´ÉÇÏ´Ù¸é ÀÌ °ªÀ» 0 ¸»°í ´Ù¸¥
*                            °ªÀ¸·Î ÃʱâÈ­ÇØ¾ß ÇÑ´Ù(¿¹¸¦ µé¾î, 10°³ÀÇ ÀÚ¿øÀÌ °¡¿ëÇÏ´Ù¸é ¼¼¸¶Æ÷¾î¸¦
*                            10À¸·Î ÃʱâÈ­ÇØ¾ß ÇÒ °ÍÀÌ´Ù).
*
* ¸®Åϰª     : != (void *)0  »ý¼ºÇÑ ¼¼¸¶Æ÷¾î¿¡ ´ëÇÑ À̺¥Æ® ÄÁÆ®·Ñ ºí·Ï(OS_EVENT)À» °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*
*              == (void *)0  À̺¥Æ® ÄÜÆ®·Ñ ºí·ÏÀ» »ç¿ëÇÒ ¼ö ¾øÀ½.
*********************************************************************************************************
*/

OS_EVENT *OSSemCreate (INT16U cnt)
{
    OS_EVENT *pevent;


    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                              /* ´ÙÀ½¹ø ÀÚÀ¯ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» ¾ò´Â´Ù  */
    if (OSEventFreeList != (OS_EVENT *)0) {                /* ÀÚÀ¯ ECB Ç®ÀÌ ºñ¾ú´ÂÁö È®ÀÎ              */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {                         /* À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» ¾ò´Â´Ù              */
        pevent->OSEventType = OS_EVENT_TYPE_SEM;
        pevent->OSEventCnt  = cnt;                         /* ¼¼¸¶Æ÷¾î ÃʱⰪ ¼³Á¤                     */
        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 OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* À̺¥Æ® ºí·Ï ŸÀÔ Á¡°Ë                         */
        OS_EXIT_CRITICAL();
        *err = OS_ERR_EVENT_TYPE;
    }
    if (pevent->OSEventCnt > 0) {                     /* Ä«¿îÅÍ °ªÀÌ ¾ç¼öÀ̸é ÀÚ¿øÀ» »ç¿ëÇÒ ¼ö ÀÖÀ½    */
        pevent->OSEventCnt--;                         /* Ä«¿îÅÍ °ªÀÌ ¾ç¼öÀ϶§¸¸ °ªÀ» °¨¼ÒÇÑ´Ù          */
        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_SEM;        /* ÀÚ¿øÀ» »ç¿ëÇÒ ¼ö ¾øÀ½. ¼¼¸¶Æ÷¾î¸¦ ±â´Ù¸²      */
        OSTCBCur->OSTCBDly      = timeout;            /* TCB¿¡ ŸÀӾƿôÀ» ÀúÀå                         */
        OSEventTaskWait(pevent);                      /* ŸÀӾƿôÀ̳ª À̺¥Æ®¸¦  ±â´Ù¸®µµ·Ï ŽºÅ© ´ë±â */
        OS_EXIT_CRITICAL();
        OSSched();                                    /* ´ÙÀ½ ½ÇÇà Áغñ»óŰ¡ µÈ ¿ì¼±¼øÀ§ °áÁ¤         */
        OS_ENTER_CRITICAL();
        if (OSTCBCur->OSTCBStat & OS_STAT_SEM) {  /* ¾ÆÁ÷µµ À̺¥Æ®¸¦ ±â´Ù¸°´Ù¸é ŸÀӾƿôÀÌ ¹ß»ýÇÑ °ÍÀÓ */
            OSEventTO(pevent);
            OS_EXIT_CRITICAL();
            *err = OS_TIMEOUT;                    /* ŸÀӾƿô ±â°£ ³»¿¡ À̺¥Æ®°¡ ¹ß»ýÇÏÁö ¾Ê¾ÒÀ½À» ¾Ë¸²*/
        } else {
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
            OS_EXIT_CRITICAL();
            *err = OS_NO_ERR;
        }
    }
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                            ¼¼¸¶Æ÷¾î ¹Ýȯ
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¼¼¸¶Æ÷¾î¿¡ ½ÅÈ£¸¦ º¸³½´Ù(½Ã±×³Îµå »óÅ·Π¸¸µç´Ù).
*
* Àü´ÞÀÎÀÚ   : pevent        ÇØ´ç ¼¼¸¶Æ÷¾îÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*
*
* ¸®Åϰª     : OS_NO_ERR          È£ÃâÀÌ ¼º°øÇؼ­ ¼¼¸¶Æ÷¾î·Î ½ÅÈ£¸¦ º¸³ÂÀ½.
*              OS_SEM_OVF         ¼¼¸¶Æ÷¾î Ä«¿îÅͰ¡ ÇѰ踦 ³Ñ¾úÀ½. Áï, OSSemAccept()³ª OSSemPend()¸¦ 
*                                 È£ÃâÇØ¼­ ¼¼¸¶Æ÷¾î¸¦ ±â´Ù¸®´Â Ƚ¼öº¸´Ù ÀÚÁÖ ½ÅÈ£¸¦ º¸³Â´Ù´Â °ÍÀÌ´Ù.
*
*              OS_ERR_EVENT_TYPE  ¼¼¸¶Æ÷¾î¿¡ ´ëÇÑ Æ÷ÀÎÅ͸¦ ÁöÁ¤ÇÏÁö ¾Ê¾ÒÀ½.
*********************************************************************************************************
*/

INT8U OSSemPost (OS_EVENT *pevent)
{
    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* À̺¥Æ® ºí·Ï ŸÀÔ Á¡°Ë                    */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
    }
    if (pevent->OSEventGrp) {                              /* ¾Æ¹« ŽºÅ©³ª ¼¼¸¶Æ÷¾î¸¦ ±â´Ù¸®´ÂÁö È®ÀÎ */
        OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM);    /* ´ë±â Áß ÃÖ¿ì¼±¼øÀ§ ŽºÅ©¸¦ Áغñ»óÅ·ΠÇÔ*/
        OS_EXIT_CRITICAL();
        OSSched();                                    /* ½ÇÇà Áغñ»óŠŽºÅ© Áß ÃÖ»óÀ§ ¿ì¼±¼øÀ§ °áÁ¤  */
        return (OS_NO_ERR);
    } else {
        if (pevent->OSEventCnt < 65535) {             /* ¼¼¸¶Æ÷¾î ¿À¹öÇ÷ο찡 ¹ß»ýÇÏÁö ¾ÊÀ» °ÍÀ» È®ÀÎ */
            pevent->OSEventCnt++;                     /* À̺¥Æ®¸¦ µî·ÏÇϱâ À§ÇØ ¼¼¸¶Æ÷¾î Ä«¿îÆ® Áõ°¡   */
            OS_EXIT_CRITICAL();
            return (OS_NO_ERR);
        } else {                                      /* ¼¼¸¶Æ÷¾î Ä«¿îÅͰªÀÌ ÃÖ´ë°ª¿¡ µµ´ÞÇßÀ½         */
            OS_EXIT_CRITICAL();
            return (OS_SEM_OVF);
        }
    }
}
/*
*********************************************************************************************************
*                                         ¼¼¸¶Æ÷¾î »óÅ ¾ò±â
*
* ¼³¸í       : ÀÌ ÇÔ¼ö´Â ¼¼¸¶Æ÷¾î¿¡ ´ëÇÑ Á¤º¸¸¦ ¾ò¾î³½´Ù.
*
* Àü´ÞÀÎÀÚ   : pevent        ÇØ´ç ¼¼¸¶Æ÷¾îÀÇ À̺¥Æ® ÄÁÆ®·Ñ ºí·ÏÀ» °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*
*
*              pdata         ¼¼¸¶Æ÷¾î¿¡ ´ëÇÑ Á¤º¸¸¦ ÀúÀåÇÒ ±¸Á¶Ã¼¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ.
*
*
* ¸®Åϰª     : OS_NO_ERR          È£ÃâÀÌ ¼º°øÇؼ­ ¼¼¸¶Æ÷¾î Á¤º¸¸¦ ¾ò¾î³ÂÀ½.
*              OS_ERR_EVENT_TYPE  ¼¼¸¶Æ÷¾î°¡ ¾Æ´Ñ ±¸Á¶Ã¼ÀÇ Á¤º¸¸¦ ¾Ë·Á ÇßÀ½.
*********************************************************************************************************
*/

INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)
{
    INT8U  i;
    INT8U *psrc;
    INT8U *pdest;
    
    
    OS_ENTER_CRITICAL();
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* À̺¥Æ® ºí·Ï ŸÀÔ Á¡°Ë                    */
        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->OSCnt      = pevent->OSEventCnt;                /* ¼¼¸¶Æ÷¾î Ä«¿îÅͰªÀ» ¾ò´Â´Ù               */
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif