/*
*********************************************************************************************************
*                                     SERIAL (BYTE) COMMUNICATION
*
*                         (c) Copyright 2007-2009; Micrium, Inc.; Weston, FL
*
*               All rights reserved.  Protected by international copyright laws.
*               Knowledge of the source code may NOT be used to develop a similar product.
*               Please help us continue to provide the Embedded community with the finest
*               software available.  Your honesty is greatly appreciated.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                     SERIAL (BYTE) COMMUNICATION
*
*                                       OPERATING SYSTEM LAYER
*                                          Micrium uC/OS-III
*
* Filename      : serial_os.c
* Version       : V2.00
* Programmer(s) : FGK
*                 FT
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                            INCLUDE FILES
*********************************************************************************************************
*/

#include  <serial.h>
#include  <serial_os.h>
#include  <os.h>

/*
*********************************************************************************************************
*                                              DEFINES
*********************************************************************************************************
*/

#define  SERIAL_OS_MAX_NBR_SEM                  ((4u + SERIAL_CFG_TX_DESC_NBR) * SERIAL_CFG_MAX_NBR_IF)


/*
*********************************************************************************************************
*                                       LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

static  MEM_POOL  OS_SemPool;


/*$PAGE*/
/*
*********************************************************************************************************
*                                           SerialOS_Init()
*
* Description : Initialize OS layer.
*
* Argument(s) : perr        Pointer to variable that will receive the return error code from this function :
*
*                               SERIAL_OS_ERR_NONE          Initialization of OS layer successful.
*                               SERIAL_OS_ERR_INIT          Initialization of OS layer failed.
*
* Return(s)   : None.
*
* Caller(s)   : Serial_Init().
*
* Note(s)     : None.
*********************************************************************************************************
*/

void  SerialOS_Init (SERIAL_ERR  *perr)
{
    LIB_ERR     lib_err;
    CPU_SIZE_T  octects_reqd;


    Mem_PoolCreate((MEM_POOL    *)&OS_SemPool,
                   (void        *) 0,
                   (CPU_SIZE_T   ) 0u,
                   (CPU_SIZE_T   ) SERIAL_OS_MAX_NBR_SEM,
                   (CPU_SIZE_T   ) sizeof(OS_SEM),
                   (CPU_SIZE_T   ) 1u,
                   (CPU_SIZE_T  *)&octects_reqd,
                   (LIB_ERR     *)&lib_err);

    if (lib_err != LIB_MEM_ERR_NONE) {
       *perr = SERIAL_OS_ERR_INIT;
        return;
    }

   *perr = SERIAL_OS_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        SerialOS_SemCreate()
*
* Description : Create a semaphore.
*
* Argument(s) : cnt         Initial value for the semaphore.
*
* Return(s)   : Pointer to semaphore, if NO errors.
*               Pointer to NULL,      otherwise.
*
* Caller(s)   : Serial_Wr().
*
* Note(s)     : None.
*********************************************************************************************************
*/

void  *SerialOS_SemCreate (CPU_INT16U  cnt)
{
    OS_SEM   *psem;
    LIB_ERR   lib_err;
    OS_ERR    os_err;


    psem = (OS_SEM *)Mem_PoolBlkGet((MEM_POOL    *)&OS_SemPool,
                                    (CPU_SIZE_T   ) sizeof(OS_SEM),
                                    (LIB_ERR     *)&lib_err);

    if (lib_err != LIB_MEM_ERR_NONE) {
        return ((void *)0);
    }

    OSSemCreate((OS_SEM      *)psem,
                (CPU_CHAR    *)0,
                (OS_SEM_CTR   )cnt,
                (OS_ERR      *)&os_err);

    if (os_err != OS_ERR_NONE) {
        Mem_PoolBlkFree((MEM_POOL  *)&OS_SemPool,
                        (void      *) psem,
                        (LIB_ERR   *)&lib_err);
        return ((void *)0);
    }

    return ((void *)psem);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                          SerialOS_SemDel()
*
* Description : Delete a semaphore.
*
* Argument(s) : psem        Pointer to semaphore to delete.
*
* Return(s)   : None.
*
* Caller(s)   : Serial_WrCallback().
*
* Note(s)     : (1) Always delete the semaphore even if tasks are pending on it.
*
*               (2) MUST NOT be called within a critical section.
*********************************************************************************************************
*/

void  SerialOS_SemDel (void  *psem)
{
    LIB_ERR  lib_err;
    OS_ERR   os_err;


    OSSemPendAbort((OS_SEM  *)psem,
                   (OS_OPT   )OS_OPT_PEND_ABORT_ALL,
                   (OS_ERR  *)&os_err);

    OSSemDel((OS_SEM  *)psem,
             (OS_OPT   )OS_OPT_DEL_ALWAYS,
             (OS_ERR  *)&os_err);

    Mem_PoolBlkFree((MEM_POOL  *)&OS_SemPool,
                    (void      *) psem,
                    (LIB_ERR   *)&lib_err);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                         SerialOS_SemWait()
*
* Description : Wait for a semaphore to become available.
*
* Argument(s) : psem        Pointer to semaphore to wait.
*
*               timeout_ms  Optional timeout period in milliseconds. If specified 0, wait indefinitely.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               SERIAL_OS_ERR_NONE              The wait on semaphore was successful.
*                               SERIAL_OS_ERR_TIMEOUT           Semaphore not recv'd within specified 'timeout'.
*                               SERIAL_OS_ERR_SIGNAL            Waiting on semaphore could not be performed.
*
* Return(s)   : None.
*
* Caller(s)   : Serial_Wr().
*
* Note(s)     : None.
*********************************************************************************************************
*/

void  SerialOS_SemWait (void        *psem,
                        CPU_INT32U   timeout_ms,
                        SERIAL_ERR  *perr)
{
    OS_TICK  ticks;
    OS_ERR   os_err;


    ticks = (timeout_ms * OSCfg_TickRate_Hz + (DEF_TIME_NBR_mS_PER_SEC - 1u)) / DEF_TIME_NBR_mS_PER_SEC;

    (void)OSSemPend((OS_SEM   *) psem,
                    (OS_TICK   ) ticks,
                    (OS_OPT    ) OS_OPT_PEND_BLOCKING,
                    (CPU_TS   *) 0,
                    (OS_ERR   *)&os_err);

    switch (os_err) {
        case OS_ERR_NONE:
            *perr = SERIAL_OS_ERR_NONE;
             break;

        case OS_ERR_TIMEOUT:
            *perr = SERIAL_OS_ERR_TIMEOUT;
             break;

        default:
            *perr = SERIAL_OS_ERR_SIGNAL;
             break;
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        SerialOS_SemTryLock()
*
* Description : Try to acquire semaphore if available.
*
* Argument(s) : psem        Pointer to semaphore to acquire.
*
* Return(s)   : DEF_OK,   if semaphore acquired.
*               DEF_FAIL, otherwise.
*
* Caller(s)   : Serial_WrAsync().
*
* Note(s)     : None.
*********************************************************************************************************
*/

CPU_BOOLEAN  SerialOS_SemTryLock (void  *psem)
{
    OS_ERR  os_err;


    (void)OSSemPend((OS_SEM   *) psem,
                    (OS_TICK   ) 0u,
                    (OS_OPT    ) OS_OPT_PEND_NON_BLOCKING,
                    (CPU_TS   *) 0,
                    (OS_ERR   *)&os_err);

    if (os_err != OS_ERR_NONE) {
        return (DEF_FAIL);
    }

    return (DEF_OK);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        SerialOS_SemSignal()
*
* Description : Signal a semaphore.
*
* Argument(s) : psem        Pointer to semaphore to signal.
*
* Return(s)   : DEF_OK,   if semaphore signaled.
*               DEF_FAIL, otherwise.
*
* Caller(s)   : Serial_WrCallback().
*
* Note(s)     : None.
*********************************************************************************************************
*/

CPU_BOOLEAN  SerialOS_SemSignal (void  *psem)
{
    OS_ERR  os_err;


    (void)OSSemPost((OS_SEM  *)psem,
                    (OS_OPT   )OS_OPT_POST_1,
                    (OS_ERR  *)&os_err);

    if (os_err != OS_ERR_NONE) {
        return (DEF_FAIL);
    }

    return (DEF_OK);
}
