/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    GKI_FreeRTOS.c
* Description:  OS abstraction layer to FreeRTOS
*
* Copyright (c) 2012 Amped'RF Inc., AR Technology  All rights reserved.
*******************************************************************************/
#include "Common.h"
#ifdef FREE_RTOS

#if !defined(MODULE_IS_APPL)
#include "target.h"
#include "btm_int.h"
#include "TM_FlashManager.h"
#endif


// forward references
void ShowTaskSpace(void);
void ShowTaskSpaceShort(void);


/*******************************************************************************
* Function         GKI mem pools
* Description      Initilize all GKI memory pools
* Returns          none
*******************************************************************************/
tGKI_BufPool GKI_BufPool[GKI_BUF_POOL_NUM]={
    "GkiMem0",      GKI_BUF0_MAX,  GKI_BUF0_SIZE,    NULL,  // GKI_POOL_ID_0
    "GkiMem1",      GKI_BUF1_MAX,  GKI_BUF1_SIZE,    NULL,  // GKI_POOL_ID_1
    "GkiMem2",      GKI_BUF2_MAX,  GKI_BUF2_SIZE,    NULL,  // GKI_POOL_ID_2
    "GkiMem3",      GKI_BUF3_MAX,  GKI_BUF3_SIZE,    NULL,  // GKI_POOL_ID_3
    "GkiMem4",      GKI_BUF4_MAX,  GKI_BUF4_SIZE,    NULL,  // GKI_POOL_ID_4
};
tpGKI_MemPool UL_MemPool[GKI_BUF_POOL_NUM];


/*******************************************************************************
* Global area
*******************************************************************************/
tGKI_Data GKI_Data={0};
tGKI_Module GKI_Module[MAX_MODULES]={0};
#ifndef DEVKIT
#define TM_EXPIRATION_MARGIN 16 // in ticks
#endif

// Tick units
u32 TM_TICKS_PER_SECOND         = 20000;
u32 TM_TICKS_PER_MILLISECOND    = (20000/1000);


/*******************************************************************************
* Function Name  : GKI_CreateModule
* Description    : Creates a task and attaches an associated Signal queue
*******************************************************************************/
bool GKI_CreateModule(u16 id, tGKI_Task pvTaskCode,
                           const char * pcName,
                           u16 queueSize,
                           u16 usStackDepth,
                           u16 uxPriority)
{
    char msg[60];

    if (id < MAX_MODULES)
    {
        strncpy(GKI_Module[id].Name, pcName, configMAX_TASK_NAME_LEN);
        GKI_Module[id].QueueHandle = xQueueCreate(queueSize, 4);
        if (!GKI_Module[id].QueueHandle) {
            sprintf(msg, "Cannot create %s task queue", pcName);
            GKI_FATAL(msg);
            return false;
        }
        if (pdPASS != xTaskCreate(pvTaskCode,  (signed char const *)pcName,  usStackDepth/4,
                                  NULL, uxPriority, &GKI_Module[id].TaskHandle))
        {
            sprintf(msg, "Cannot create %s task", pcName);
            GKI_FATAL(msg);
            return false;
        }
        GKI_Module[id].StackSize = usStackDepth;
        GKI_Data.TotalStackSize += usStackDepth;
        GKI_Data.TotalQueueSize += queueSize * 4;
        GKI_Module[id].Initialized = true;
        return true;
    }
    return false;
}



/*******************************************************************************
* Function Name  : GKI_CreatePool
* Description    : Create a memory pool
*******************************************************************************/
tpGKI_Pool GKI_CreatePool(const char *PoolName, u16 NoOfBlocks, u16 BlockSize, tGKI_PoolNotifyFunc NotifyFunc)
{
    tCriticalSection    CriticalSection;
    tpGKI_Pool          pPool;
    tpGKI_MemBlock      pMemBlock;
    tpGKI_MemBlock      pNextMemBlock;
    uint32              ReqSize;
    uint32              i;
    void               *pMem;

    // Reserve pool memory
    BlockSize = (BlockSize + 3) & (~0x03);          // Align to 4 byte boundary
    ReqSize = sizeof(tGKI_MemPool) + (NoOfBlocks *
      (BlockSize + sizeof(tGKI_MemBlock)));
    pMem = pvPortMalloc(ReqSize);

    // Error checking
    if (pMem==NULL) {
        char msg[50];
        sprintf(msg, "Cannot Create Pool %s", PoolName);
        GKI_FATAL(msg);
        return NULL;
    }

    // Get a typed pointer
    pPool = (tpGKI_Pool)pMem;

    // Enter critical section
    GKI_ENTER_CRITICAL_SECTION(CriticalSection);

    // Register pool in category
    pPool->pNextPool = GKI_Data.MemPoolList;
    GKI_Data.MemPoolList = pPool;

    // Init pool
    pPool->Name       = (char *)PoolName;
    pPool->NoOfBlocks = NoOfBlocks;
    pPool->BlockSize  = BlockSize;
    pPool->NotifyFunc = NotifyFunc;
    pPool->pFreeBlock = (tpGKI_MemBlock)(pPool + 1);
    pPool->BlockUse   = 0;
    pPool->BlockUsePeak = 0;


    // Init blocks
    pNextMemBlock = pPool->pFreeBlock;
    for (i=0; i<NoOfBlocks; i++)
    {
        pMemBlock = pNextMemBlock;
        pMemBlock->pMemHeader = pMemBlock;
        pMemBlock->pOwnerPool = pPool;
        pNextMemBlock = (tpGKI_MemBlock)((uint8*)pMemBlock + sizeof(tGKI_MemBlock) + BlockSize);
        pMemBlock->pNext = pNextMemBlock;
    }
    pPool->TopAddress = pMemBlock->pNext;
    pMemBlock->pNext  = NULL;

    GKI_Data.TotalPoolSize += ReqSize;

    // Exit critical section
    GKI_EXIT_CRITICAL_SECTION(CriticalSection);

    return pPool;
}



/*******************************************************************************
* Function Name  : GKI_GetFromPool
* Description    : Get a memory block from pool
*******************************************************************************/
void *GKI_GetFromPool(tpGKI_Pool pPool)
{
    tCriticalSection    CriticalSection;
    tpGKI_MemBlock      pMemBlock;

    GKI_ASSERT(pPool!=NULL, "Invalid Pool");

    GKI_ENTER_CRITICAL_SECTION(CriticalSection);

    // Link next free block out of the pool
    pMemBlock = pPool->pFreeBlock;
    if (pMemBlock == NULL)
    {
        GKI_EXIT_CRITICAL_SECTION(CriticalSection);
        return NULL;
    }

    pPool->pFreeBlock = pMemBlock->pNext;
    pPool->BlockUse++;
    if (pPool->BlockUse > pPool->BlockUsePeak) {
        pPool->BlockUsePeak = pPool->BlockUse;
    }


    // Check magic number in pool head
#ifdef DEBUG
    GKI_ASSERT(pPool->pFreeBlock != GKI_INVALID_PTR, "");
    GKI_ASSERT(pMemBlock != GKI_INVALID_PTR, "");
    GKI_ASSERT(pMemBlock->pNext != GKI_INVALID_PTR, "");
#endif


    // Set an invalid known pointer
    pMemBlock->pNext = GKI_INVALID_PTR;

    if ((uint32)pMemBlock >= (uint32)pPool->TopAddress)
    {
        GKI_FATAL("Block outside of pool");
        pMemBlock = NULL;
    }

    if (pMemBlock != pMemBlock->pMemHeader)
    {
        GKI_FATAL("Invalid block header");
        pMemBlock = NULL;
    }

    GKI_EXIT_CRITICAL_SECTION(CriticalSection);

    if(pMemBlock!=NULL)
        return (void*)(pMemBlock + 1);
    else
        return NULL;
}


/*******************************************************************************
* Function Name  : GKI_ReturnToPool
* Description    : Return memory block to pool
*******************************************************************************/
void GKI_ReturnToPool(void *p)
{
    tCriticalSection    CriticalSection;
    tpGKI_MemBlock      pMemBlock;
    tpGKI_Pool          pPool;

    // Check the pointer
    GKI_ASSERT(p != NULL, "ReturnToPool(NULL)");
    ASSERT_VALID_RAM(p, "Invalid Memory Block");

    // Go to the block head
    pMemBlock = (tpGKI_MemBlock)(p) - 1;

    if (pMemBlock != pMemBlock->pMemHeader)
        GKI_FATAL("Invalid block header");

    // Check magic number in pool head
    if (pMemBlock->pNext != GKI_INVALID_PTR)
    {
        if (pMemBlock->pMemHeader == pMemBlock) {
            GKI_ASSERT(0, "Memory block already deallocated");
            return;
        }
        else
            GKI_ASSERT(0, "Corrupted memory block");
    }

    // Figure out the pool
    pPool = pMemBlock->pOwnerPool;


    // Return the block to the pool
    GKI_ENTER_CRITICAL_SECTION(CriticalSection);
    pMemBlock->pNext = pPool->pFreeBlock;
    pPool->pFreeBlock = pMemBlock;
    pPool->BlockUse--;
    GKI_EXIT_CRITICAL_SECTION(CriticalSection);

    // Notify pool owner
    if (pPool->NotifyFunc != NULL)
    {
        // Check that we are not executing in ISR or FIQ mode
        GKI_ASSERT_USER_MODE();

        // Call notifcation function
        pPool->NotifyFunc(pPool);
    }
}



/*******************************************************************************
* Function Name  : GKI_GetCurrentTaskId
* Description    : Get current task ID
*******************************************************************************/
uint16 GKI_GetCurrentTaskId(void)
{
    xTaskHandle Handle = xTaskGetCurrentTaskHandle();
    for (int i=0; i<MAX_MODULES; i++) {
        if (Handle == GKI_Module[i].TaskHandle)
            return i;
    }
    return 0xFFFF;
}


/*******************************************************************************
* Function Name  : GKI_GetCurrentModuleId
* Description    : Get current module ID
*******************************************************************************/
uint16 GKI_GetCurrentModuleId(void)
{
    xTaskHandle Handle = xTaskGetCurrentTaskHandle();
    for (int i=0; i<MAX_MODULES; i++) {
        if (Handle == GKI_Module[i].TaskHandle)
            return i;
    }
    return 0xFFFF;
}


/*******************************************************************************
* Function Name  : GKI_GetCurrentTaskId
* Description    : Get current task ID
*******************************************************************************/
xQueueHandle GKI_GetCurrentTaskQueue(void)
{
    xTaskHandle Handle = xTaskGetCurrentTaskHandle();
    for (int i=0; i<MAX_MODULES; i++) {
        if (Handle == GKI_Module[i].TaskHandle)
            return GKI_Module[i].QueueHandle;
    }
    return NULL;
}


/*******************************************************************************
* Function Name  : GKI_AllocSignal
* Description    : Allocate Signal
*******************************************************************************/
tGKI_Signal* GKI_AllocSignal(tGKI_SignalNo SignalNo, tGKI_DataSize DataSize)
{
    tBP_Signal *pSignal;

    // Enter critical code
    ENTER_CRITICAL();

    // Allocate a long signal
    if (DataSize > GKI_SHORT_SIGNAL_SIZE)
    {
        // Make sure we fit in a long signal
        GKI_ASSERT(DataSize < GKI_LONG_SIGNAL_SIZE, "Too long signal");

        pSignal = GKI_Data.FreeLongSignalList;
        if (pSignal == NULL)
        {
            EXIT_CRITICAL();
            GKI_FATAL("OutOfLongSignals");
            return NULL;
        }

        // Take it out of free list
        BP_Data.FreeLongSignalList = pSignal->Head.pNextSignal;
    }

    // Allocate a short signal
    else
    {
        pSignal = BP_Data.FreeShortSignalList;
        if (pSignal == NULL)
        {
            // Try a long signal instead
            pSignal = GKI_Data.FreeLongSignalList;
            if (pSignal == NULL)
            {
                EXIT_CRITICAL();
                GKI_FATAL("OutOfLongSignals");
                return NULL;
            }

            // Take it out of free list
            GKI_Data.FreeLongSignalList = pSignal->Head.pNextSignal;
        }

        // Take it out of free list
        else
        {
            GKI_Data.FreeShortSignalList = pSignal->Head.pNextSignal;
        }
    }

    // Check the numbers
    GKI_ASSERT_VALID_PTR(pSignal);

    // Invalidate the next pointer
    pSignal->Head.pNextSignal = GKI_INVALID_PTR;

    // Set up the signal number
    pSignal->Head.SignalNumber = SignalNo;

    // Set up the data size
    pSignal->Head.DataSize = DataSize;

    // Set up the owner
    pSignal->Head.OwnerTaskId = GKI_GetCurrentTaskId();

    // Exit critical code
    EXIT_CRITICAL();

    return pSignal;
}



/*******************************************************************************
* Function Name  : GKI_IsrAllocSignal
* Description    : Allocate Signal within ISR
*******************************************************************************/
tGKI_Signal* GKI_IsrAllocSignal(tGKI_SignalNo SignalNo, tGKI_DataSize DataSize)
{
    tGKI_Signal* pSignal;

    // Enter critical code
    ENTER_CRITICAL();

    // Allocate a long signal
    if (DataSize > GKI_SHORT_SIGNAL_SIZE)
    {
        // Make sure we fit in a long signal
        GKI_ASSERT(DataSize < GKI_LONG_SIGNAL_SIZE, "");

        pSignal = GKI_Data.FreeLongSignalList;
        if (pSignal == NULL)
        {
            EXIT_CRITICAL();
            GKI_FATAL("OutOfLongSignals");
            return NULL;
        }

        // Take it out of free list
        GKI_Data.FreeLongSignalList = pSignal->Head.pNextSignal;
    }

    // Allocate a short signal
    else
    {
        pSignal = GKI_Data.FreeShortSignalList;
        if (pSignal == NULL)
        {
            // Try a long signal instead
            pSignal = GKI_Data.FreeLongSignalList;
            if (pSignal == NULL)
            {
                EXIT_CRITICAL();
                GKI_FATAL("OutOfShortSignals");
                return NULL;
            }

            // Take it out of free list
            GKI_Data.FreeLongSignalList = pSignal->Head.pNextSignal;
        }
        else
        {
            // Take it out of free list
            GKI_Data.FreeShortSignalList = pSignal->Head.pNextSignal;
        }
    }

    // Check the numbers
    GKI_ASSERT_VALID_PTR(pSignal);

    // Invalidate the next pointer
    pSignal->Head.pNextSignal  = GKI_INVALID_PTR;

    // Set up the signal number
    pSignal->Head.SignalNumber = SignalNo;

    // Set up the data size
    pSignal->Head.DataSize = DataSize;

    // Set up the owner
    pSignal->Head.OwnerTaskId = ID_SYS;

    // Exit critical code
    EXIT_CRITICAL();

    return pSignal;
}



/*******************************************************************************
* Function Name  : GKI_ReleaseSignal
* Description    : Release signal
*******************************************************************************/
void GKI_ReleaseSignal(tGKI_Signal *pSignal)
{
    // Enter critical code
    ENTER_CRITICAL();

    // Check that it isn't a NULL signal
    GKI_ASSERT(pSignal != NULL, "");

    // Check the numbers
    GKI_ASSERT_SIG_NUMBER(pSignal->Head.SignalNumber);

    // Check that signal is not in queue already
    GKI_ASSERT_INVALID_PTR(pSignal->Head.pNextSignal);

    // Check that it is the owner that is trying to send it
    //GKI_ASSERT_EXEC_TID(pSignal->Head.OwnerTaskId);

    // Check that it is not in the saved queue
    //GKI_ASSERT(GKI_Data.TCB[GKI_Data.ExecutingTaskId].SavedQueueLast != pSignal, "");

    pSignal->Head.SignalNumber = GKI_INVALID_SIGNAL_NUMBER;
    pSignal->Head.OwnerTaskId  = GKI_INVALID_TID;

    // Handle Short Signal
    if ((pSignal >= (tGKI_Signal*)&GKI_Data.ShortSignals[0]) &&
        (pSignal <= (tGKI_Signal*)&GKI_Data.ShortSignals[GKI_NO_OF_SHORT_SIGNALS]))
    {
        // Put back in free list
        pSignal->Head.pNextSignal = GKI_Data.FreeShortSignalList;
        GKI_Data.FreeShortSignalList = pSignal;

    }

    // Handle Long Signal
    else if ((pSignal >= (tGKI_Signal*)&GKI_Data.LongSignals[0]) &&
        (pSignal <= (tGKI_Signal*)&GKI_Data.LongSignals[GKI_NO_OF_LONG_SIGNALS]))
    {
        // Put back in free list
        pSignal->Head.pNextSignal = GKI_Data.FreeLongSignalList;
        GKI_Data.FreeLongSignalList = pSignal;
    }

    // Unknown signal type
    else
    {
        GKI_ASSERT(false, "UnknownSignal");
    }


    // Exit critical code
    EXIT_CRITICAL();
}




/*******************************************************************************
* Function Name  : GKI_Receive
* Description    : Wait for message for current module
*******************************************************************************/
tGKI_Signal *GKI_Receive(void)
{
    xQueueHandle Q;
    u32     SigAddress;

    Q = GKI_GetCurrentTaskQueue();
    xQueueReceive(Q, &SigAddress, portMAX_DELAY);

#ifdef TEST_RTOS
    char * GetSignalName(uint16);
    static char msg[32];
    tGKI_Signal *pSignal;
    pSignal = (tGKI_Signal *)SigAddress;
    sprintf(msg, "%6d rcv %3.3s-->%3.3s: %s\r\n", TM_GetTicks()/TM_TICKS_PER_MILLISECOND,
            GKI_GetModuleNameFromId(pSignal->Head.SenderTaskId), GKI_ModuleName(),
            GetSignalName(pSignal->Head.SignalNumber));
    GKI_putstring(msg);
#endif

    return (tGKI_Signal *)SigAddress;
}




/*******************************************************************************
* Function Name  : GKI_RequestSystemShutdown
* Description    : Wait for message for current module
*******************************************************************************/
void GKI_RequestSystemShutdown(uint32 Reason)
{
    void OS_Shutdown(void);
    GKI_Data.ShutdownRequested  = true;
    GKI_Data.ShutdownReason     = Reason;
    OS_Shutdown();
}



/*******************************************************************************
* Function Name  : GKI_ReportTaskShutdownDone
* Description    : Wait for message for current module
*******************************************************************************/
void GKI_ReportTaskShutdownDone(void)
{
    tpGKI_Signal pSignal;

    pSignal = GKI_AllocSignal(SIG_BP_SHUTDOWN_DONE, 0);
    GKI_Send(GKI_KERNEL_TID, pSignal);
}



/*******************************************************************************
* Function Name  : GKI_SystemFatal
* Description    : Wait for message for current module
*******************************************************************************/
void GKI_SystemFatal(uint32 Reason, char *pFileName, uint16 LineNo)
{
    GKI_Data.ExecutingTaskId = ID_SYS;

    // Call the Fatal function if one exists
    if (GKI_Data.FatalFunc != NULL)
        GKI_Data.FatalFunc(Reason, pFileName, LineNo);
    else
        GKI_ASSERT(false, "");

    // if it was not handled before this point, make sure we do something
    GKI_Data.FatalFunc = 0;
    GKI_Data.FatalFunc(Reason, pFileName, LineNo); // Jump to the reset vector

}


/*******************************************************************************
* Function Name  : GKI_ResetPool
* Description    : Reset pool to its initial state
*******************************************************************************/
void GKI_TakeOwnershipOfSignal(tGKI_Signal *pSignal)
{
    // Check that we are not executing in ISR or FIQ mode
    GKI_ASSERT_USER_MODE();

    // Check that it isn't a NULL signal
    GKI_ASSERT(pSignal != NULL, "");

    // Check the numbers
    GKI_ASSERT_SIG_NUMBER(pSignal->Head.SignalNumber);

    // Check that signal is not in queue
    //GKI_ASSERT_INVALID_PTR(pSignal->Head.pNextSignal);

    pSignal->Head.OwnerTaskId = GKI_Data.ExecutingTaskId;
}



/*******************************************************************************
* Function Name  : GKI_GetExecutingTaskId
* Description    : Get current executing task ID
*******************************************************************************/
tGKI_TaskId GKI_GetExecutingTaskId(void)
{
    return GKI_GetCurrentTaskId();
}



/*******************************************************************************
* Function Name  : GKI_ResetPool
* Description    : Reset pool to its initial state
*******************************************************************************/
void GKI_ResetPool(tpGKI_Pool pPool)
{
    tCriticalSection    CriticalSection;
    tpGKI_MemBlock      pMemBlock;
    tpGKI_MemBlock      pNextMemBlock;
    uint32              i;

    GKI_ENTER_CRITICAL_SECTION(CriticalSection);

    // Init blocks
    pPool->BlockUse   = 0;
    // pPool->BlockUsePeak = 0;
    pNextMemBlock = (tpGKI_MemBlock)(pPool + 1);
    for (i=0; i<pPool->NoOfBlocks; i++) {
        pMemBlock = pNextMemBlock;
        pMemBlock->pMemHeader = pMemBlock;
        pMemBlock->pOwnerPool = pPool;
        pNextMemBlock = (tpGKI_MemBlock)((uint8*)pMemBlock + sizeof(tGKI_MemBlock) + pPool->BlockSize);
        pMemBlock->pNext = pNextMemBlock;
    }
    pMemBlock->pNext  = NULL;

    GKI_EXIT_CRITICAL_SECTION(CriticalSection);
}



/*******************************************************************************
* Function Name  : GKI_InitQueue
* Description    : Initialize queue
*******************************************************************************/
void GKI_InitQueue(tGKI_Queue *pQueue)
{
    // Check that it isn't a NULL queue
    GKI_ASSERT(pQueue != NULL, "InitQ NULL");

    pQueue->p_first = NULL;
    pQueue->p_last  = NULL;
    pQueue->count  = 0;
    pQueue->limit  = 0;
}



/*******************************************************************************
* Function Name  : GKI_enqueue
* Description    : Adds to a memory block to the back of a queue (FIFO).
*******************************************************************************/
void GKI_enqueue(tGKI_Queue *pQueue, void *pMem)
{
    tCriticalSection    CriticalSection;
    tpGKI_MemBlock       pMemBlock;

    GKI_ASSERT_USER_MODE();

    // Check that it isn't a NULL queue
    GKI_ASSERT(pQueue != NULL, "Q NULL");

    // Check that it isn't a NULL pointer
    GKI_ASSERT(pMem != NULL, "");

    // Go to the block head
    pMemBlock = (tpGKI_MemBlock)(pMem) - 1;

    // Check magic number in pool head
    GKI_ASSERT(pMemBlock->pNext == GKI_INVALID_PTR, "Buffer Not Allocated");

    GKI_ENTER_CRITICAL_SECTION(CriticalSection);

    // Queue the signal in the queus
    pMemBlock->pNext = NULL;
    if (pQueue->p_first == NULL)
    {
        // No other signals in queue
        GKI_ASSERT(pQueue->p_last == NULL, "");
        pQueue->p_first = pMemBlock;
        pQueue->p_last = pMemBlock;
    }
    else
    {
        // Add after last in queue
        GKI_ASSERT(pQueue->p_last->pNext == NULL, "");
        pQueue->p_last->pNext = pMemBlock;
        pQueue->p_last = pMemBlock;
    }

    pQueue->count++;
    pMemBlock = NULL;

    // Check if there is a limit and if so remove from front
    if ((pQueue->limit != 0) && (pQueue->count > pQueue->limit))
    {
        pMemBlock = pQueue->p_first;
        if (pMemBlock != NULL)
        {
            // Take out the first in the queue
            pQueue->p_first = pMemBlock->pNext;
            if (pMemBlock->pNext == NULL) {
                pQueue->p_last = NULL;
            }
            pQueue->count--;
        }
    }

    GKI_EXIT_CRITICAL_SECTION(CriticalSection);

    // Return the front block to pool
    if (pMemBlock != NULL)
        GKI_ReturnToPool((void*)(pMemBlock+1));
}


/*******************************************************************************
* Function Name  : GKI_enqueue_head
* Description    : to a memory block to the front of a queue (LIFO).
*******************************************************************************/
void GKI_enqueue_head(tGKI_Queue *pQueue, void *pMem)
{
    tCriticalSection    CriticalSection;
    tpGKI_MemBlock       pMemBlock;

    GKI_ASSERT_USER_MODE();

    // Check that it isn't a NULL queue
    GKI_ASSERT(pQueue != NULL, "QiF Q=NULL");

    // Check that it isn't a NULL pointer
    GKI_ASSERT(pMem != NULL, "QiF p=NULL");

    // Go to the block head
    pMemBlock = (tpGKI_MemBlock)(pMem) - 1;

    // Check magic number in pool head
    GKI_ASSERT(pMemBlock->pNext == GKI_INVALID_PTR, "");

    GKI_ENTER_CRITICAL_SECTION(CriticalSection);

    // Queue the signal in the queus
    if (pQueue->p_first == NULL)
    {
        // No other signals in queue
        GKI_ASSERT(pQueue->p_last == NULL, "");
        pQueue->p_first = pMemBlock;
        pQueue->p_last = pMemBlock;
        pMemBlock->pNext = NULL;
    }
    else
    {
        // Add in front of queue
        pMemBlock->pNext = pQueue->p_first;
        pQueue->p_first = pMemBlock;
    }

    pQueue->count++;

    GKI_EXIT_CRITICAL_SECTION(CriticalSection);
}



/*******************************************************************************
* Function Name  : GKI_dequeue
* Description    : Gets  the next memory block from the queue.
*******************************************************************************/
void * GKI_dequeue(tGKI_Queue *pQueue)
{
    tCriticalSection     CriticalSection;
    tpGKI_MemBlock        pMemBlock;

    GKI_ASSERT_USER_MODE();

    // Check that it isn't a NULL signal queue
    GKI_ASSERT(pQueue != NULL, "");

    GKI_ENTER_CRITICAL_SECTION(CriticalSection);

    pMemBlock = pQueue->p_first;
    if (pMemBlock != NULL)
    {
        // Take out the first in the queue
        pQueue->p_first = pMemBlock->pNext;
        if (pMemBlock->pNext == NULL) {
            pQueue->p_last = NULL;
        }
        pQueue->count--;
    }

    GKI_EXIT_CRITICAL_SECTION(CriticalSection);

    if (pMemBlock == NULL)
        return NULL;

    pMemBlock->pNext = GKI_INVALID_PTR;

    return (void*)(pMemBlock + 1);
}



/*******************************************************************************
* Function         GKI_init
* Description      Initilize all GKI memory pools
*******************************************************************************/
void GKI_init(void)
{
    for (int i=0; i<GKI_BUF_POOL_NUM; i++)
    {
        UL_MemPool[i] = (tpGKI_Pool)GKI_CreatePool(
                                          GKI_BufPool[i].Name,
                                          GKI_BufPool[i].Num,
                                          GKI_BufPool[i].Size,
                                          (tGKI_PoolNotifyFunc)GKI_BufPool[i].NotifyFunction);
        if (UL_MemPool[i] == NULL) {
            char errbuf[30];
            sprintf(errbuf, "Gki Mem %d - No Memory", i);
            fatalc(0, errbuf);
        }
    }
    GKI_SetReady(GKI_READY_POOLS);
    GKI_putstring("-Ready POOLS\r\n");
    GKI_WaitUntilReady(GKI_READY_TM);
}


/*******************************************************************************
* Function         GKI_getbuf
* Description      Called by an application to get a free buffer which
*                  is of size greater or equal to the requested size.
* Returns          Pointer to the buffer, or NULL if none is available
*******************************************************************************/
void *GKI_getbuf (UINT16 size)
{
    tpGKI_MemPool pPool;
    void *p=NULL;
    uint8 i;

    for (i=0; i<GKI_BUF_POOL_NUM; i++) {
        pPool = UL_MemPool[i];
        if (size<=pPool->BlockSize && NULL!=(p=GKI_GetFromPool(pPool))) {
            break;
        }
    }

    return (p);
}




/*******************************************************************************
* Function         GKI_getAvailable
* Description      Called by an application to get the number of available
*                  buffers from a specific buffer pool.
* Returns          Number of available buffers
*******************************************************************************/
uint32 GKI_getAvailable(uint8 id)
{
    uint32 count = UL_MemPool[id]->NoOfBlocks - UL_MemPool[id]->BlockUse;

    return count;
}



/*******************************************************************************
* Function         GKI_IsAllocated
* Description      Check to see if buffer is allocated
* Returns          True if allocated
*******************************************************************************/
bool GKI_IsAllocated(void *p)
{
    tpGKI_MemBlock pMemBlock;

    pMemBlock = (tpGKI_MemBlock)p - 1;

    if (pMemBlock->pNext == GKI_INVALID_PTR)
        return true;
    else
        return false;
}


/*******************************************************************************
* Function         GKI_freebuf
* Description      Called by an application to return a buffer to the free pool.
* Returns          void
*******************************************************************************/
void GKI_freebuf (void *bptr)
{
    if (GKI_IsAllocated(bptr))
    {
        assertc(bptr != NULL, "Gki free buffer ptr invalid");
        GKI_ReturnToPool(bptr);
    }
}


/*******************************************************************************
* Function         GKI_getfirst
* Description      Return a pointer to the first buffer in a queue
* Returns          NULL if queue is empty, else buffer address
*******************************************************************************/
void *GKI_getfirst (GKI_BUFFER_Q *p_q)
{
    return (p_q->p_first+1);
}



/*******************************************************************************
* Function         GKI_getnext
* Description      Return a pointer to the next buffer in a queue
* Returns          NULL if no more buffers in the queue, else next buffer address
*******************************************************************************/
void *GKI_getnext (void *p_buf)
{
    return NULL;
}



/*******************************************************************************
* Function         GKI_remove_from_queue
* Description      Dequeue a buffer from the middle of the queue
* Returns          NULL if queue is empty, else buffer
*******************************************************************************/
void *GKI_remove_from_queue (GKI_BUFFER_Q *p_q, void *p_buf)
{
    tpGKI_Queue   pBPQ;
    void         *pBuf;
    bool          Found;
    u16           i;

    Found = false;
    pBPQ  = (tpGKI_Queue)p_q;

    for (i=0; i < pBPQ->count; i++)
    {
        pBuf  = GKI_dequeue(pBPQ);

        if (pBuf== p_buf) {
            // buffer found
            Found= true;
        }
        else {
            // not found, queue it back
            GKI_enqueue(pBPQ, pBuf);
        }
    }

    if (Found) {
        return p_buf;
    }
    else {
        return NULL;
    }
}



/*******************************************************************************
* Function         GKI_get_tick_count
* Description      This function returns the current system ticks
* Returns          ticks
*******************************************************************************/
u32  GKI_get_tick_count(void)
{
#ifdef STACK_ONLY
    return 0;
#else
    return RTC_GetCounter();
#endif
}



/*******************************************************************************
* Function         GKI_set_tick_timeout
* Description      Set the timeout tick value
*******************************************************************************/
void  GKI_set_tick_timeout(u32 ticks)
{
#ifdef STACK_ONLY
    RTC_AlarmValue = MAX(ticks, GKI_get_tick_count()+TM_EXPIRATION_MARGIN);
    GKI_set_tick_timeout(RTC_AlarmValue);
#else
    extern u32 RTC_AlarmValue;
    RTC_AlarmValue = MAX(ticks, GKI_get_tick_count()+TM_EXPIRATION_MARGIN);
    RTC_SetAlarm(RTC_AlarmValue);
#endif
}




/*******************************************************************************
* Function         GKI_ReserveMemory
* Description      Allocates memory from the heap
* Returns          Pointer to memory
*******************************************************************************/
uint8 *GKI_ReserveMemory(char *name, uint32 size)
{
    return (uint8 *)pvPortMalloc(size);
}


#define TMR_TIMEOUT         2000
#define TMR_ID              0x1122
#define SIG_TEXT_MESSAGE    0x1234
#define SIG_TIMEOUT         0x4321


/*******************************************************************************
* Show stack space
*******************************************************************************/
void ShowTaskSpace(void)
{
    static u8 i;
    static char msg[24];

    ENTER_CRITICAL();
    GKI_putstring("ID Task  Stack  Free\r\n");
    for (i=0; i<MAX_MODULES; i++)
    {
        if (GKI_Module[i].TaskHandle)
        {
            sprintf(msg, "%2d %-5.5s %5d %5d\r\n", i,
                GKI_Module[i].Name,
                GKI_Module[i].StackSize,
                uxTaskGetStackHighWaterMark(GKI_Module[i].TaskHandle)*4);
            GKI_putstring(msg);
        }
    }
    EXIT_CRITICAL();
}


/*******************************************************************************
* Stack check used for debugging
*******************************************************************************/
void GKI_StackCheck(void)
{
    static u16 i;
    static u16 stackHiWM;

    for (i=0; i<MAX_MODULES; i++)
    {
        if (GKI_Module[i].TaskHandle)
        {
            stackHiWM = uxTaskGetStackHighWaterMark(GKI_Module[i].TaskHandle)*4;
            if (uxTaskGetStackHighWaterMark(GKI_Module[i].TaskHandle)*4 < 16) {
                ENTER_CRITICAL();
                ShowTaskSpace();
                while (1) {
                    NOP;
                }
                EXIT_CRITICAL();
            }
        }
    }
}



/*******************************************************************************
* Show stack space (short)
*******************************************************************************/
void ShowTaskSpaceShort(void)
{
    static u8 i;
    static char msg[16];

    ENTER_CRITICAL();
    for (i=0; i<MAX_MODULES; i++)
    {
        if (GKI_Module[i].TaskHandle)
        {
            sprintf(msg, "%5d", uxTaskGetStackHighWaterMark(GKI_Module[i].TaskHandle)*4);
            GKI_putstring(msg);
        }
    }
    GKI_putstring("\r\n");
    EXIT_CRITICAL();
}


/*******************************************************************************
* Function Name  : SYS_Task
* Description    : System task
*******************************************************************************/
void SYS_Task(void *pvParameters)
{
    tGKI_Signal    *pSignal;
    tGKI_SignalNo   SigNo;
    uint8          *pData;
    tBufferHeader  *pBuf;

    // External functions
    void SU_SetUpSystemDynamicConfiguration(void);

    // Init table of valid baudrates
    TM_InitValidBaudrateTable();

    SU_SetUpSystemDynamicConfiguration();   // Dynamic config vars
#ifndef STACK_ONLY
    SU_SetCpuMHz(TM_CpuMHz);                // Setup CPU speed
    InitUart();
#endif

    pSignal = GKI_AllocSignal(SIG_OS_STARTUP, 0);
    GKI_Send(ID_TM, pSignal);

    pSignal = GKI_AllocSignal(SIG_OS_STARTUP, 0);
    GKI_Send(ID_AMP, pSignal);

    pSignal = GKI_AllocSignal(SIG_OS_STARTUP, 0);
    GKI_Send(ID_BTU, pSignal);

    pSignal = GKI_AllocSignal(SIG_OS_STARTUP, 0);
    GKI_Send(ID_APPL, pSignal);

#ifndef STACK_ONLY
    pSignal = GKI_AllocSignal(SIG_OS_STARTUP, 0);
    GKI_Send(ID_AT, pSignal);
#endif

    GKI_Data.State = eGKI_State_Running;

    //GKI_RegisterIdleFunc(Targ_Idle);      // Idle Function
    GKI_SetState(eGKI_State_TaskInit);

    while (pSignal = GKI_Receive())
    {
        pData = GKI_GetSignalDataPtr(pSignal);
        SigNo = GKI_GetSignalNo(pSignal);

        switch (SigNo) {
        case SIG_TEXT_MESSAGE:
            pBuf = (tBufferHeader  *)pSignal->Data.Transac;
            GKI_putstring((char *)pBuf);
            GKI_freebuf(pBuf);
            break;
        default:
            {
                char *msg;
                msg = GKI_AllocMemory(50);
                GKI_WaitMS(20);
                sprintf(msg, "SYS: Got unknown signal %d, 0x%04x\r\n", SigNo, SigNo);
                GKI_putstring(msg);
                GKI_ReleaseMemory(msg);
            }
            break;
        }
        GKI_ReleaseSignal(pSignal);
    }

    GKI_putstring("\r\nEnding SYS_Task\r\n");
    GKI_EndTask();
}





/*******************************************************************************
* Function         GKI_Start
* Description      Start everything
*******************************************************************************/
void GKI_Start(void)
{
    memset(&GKI_Data, 0, sizeof(GKI_Data));
    GKI_InitSignals();

    // Create tasks
    GKI_CreateModule(ID_SYS,   SYS_Task,    "SYS",  20, 500,    HIGH_PRIORITY);
    GKI_CreateModule(ID_TM,    TM_Task,     "TM",   20, 500,    HIGH_PRIORITY);
    GKI_CreateModule(ID_AMP,   AMP_Task,    "AMP",  20, 1000,   HIGH_PRIORITY);
    GKI_CreateModule(ID_BTU,   BTU_Task,    "BTU",  20, 1200,   NORMAL_PRIORITY);
#if !defined(STACK_ONLY)
    GKI_CreateModule(ID_AT,    AT_Task,     "AT",   20, 1200,   NORMAL_PRIORITY);
#endif
#if defined(MODULE_IS_APPL)
    GKI_CreateModule(ID_APPL,  APPL_Task,   "APPL", 20, 1000,   LOW_PRIORITY);
#endif


    vTaskStartScheduler();              // Start the scheduler.
    GKI_FATAL("Unexpected Exit");
}




/*******************************************************************************
* Function         GKI_SendFail
* Description      Dump bad signal
*******************************************************************************/
void GKI_SendFail(tGKI_ModuleId id, tGKI_Signal *pSignal)
{
    static char msg[60];
    ENTER_CRITICAL();
    sprintf(msg, "Err: %s GKI_Send sender=%s, owner=%s, to %d\r\n",
            GKI_ModuleName(),
            GKI_Module[pSignal->Head.SenderTaskId].Name,
            GKI_Module[pSignal->Head.OwnerTaskId].Name,
            id);
    GKI_putstring(msg);
    EXIT_CRITICAL();
}



/*******************************************************************************
* Function         GKI_Send
* Description      Send a signal
*******************************************************************************/
void GKI_Send(tGKI_ModuleId id, tGKI_Signal *pSignal)
{
    if (GKI_Module[id].Initialized)
    {

#ifdef TEST_RTOS
        char * GetSignalName(uint16);
        static char msg[64];
        sprintf(msg, "%6d snd %3.3s-->%3.3s: %s\r\n", TM_GetTicks()/TM_TICKS_PER_MILLISECOND,
                GKI_ModuleName(), GKI_GetModuleNameFromId(id),
                GetSignalName(pSignal->Head.SignalNumber));
        GKI_putstring(msg);
#endif

        pSignal->Head.SenderTaskId = GKI_GetExecutingTaskId();
        xQueueSend(GKI_Module[id].QueueHandle, &pSignal, 0);
    }
    else {
        GKI_SendFail(id, pSignal);
    }
}




/*******************************************************************************
* Function         GKI_IsrSend
* Description      Send a signal from an interrupt context
*******************************************************************************/
void GKI_IsrSend(tGKI_ModuleId id, tGKI_Signal *pSignal)
{
    signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    pSignal->Head.SenderTaskId = ID_SYS;
    xQueueSendFromISR(GKI_Module[id].QueueHandle, &pSignal, &xHigherPriorityTaskWoken);
    //if (xHigherPriorityTaskWoken == pdTRUE) {
        GKI_YieldFromISR();
    //}
}





/*******************************************************************************
* Function         GKI_WaitMS
* Description      Wait x milliseconds
*******************************************************************************/
void GKI_WaitMS(u32 ms)
{
#if defined(NATIVE_OS)
    uint32 tm=GKI_get_tick_count() + TM_TICKS_PER_SECOND*ms/1000;
    while (GKI_get_tick_count()<tm)
        ;
#elif defined(FREE_RTOS)
    vTaskDelay(ms/portTICK_RATE_MS/2);
#else
#warning GKI_WaitMS is undefined
#endif
}




/*******************************************************************************
* Function         GKI_MallocError
* Description      Report Malloc error
*******************************************************************************/
void GKI_MallocError(size_t xWantedSize)
{
    static uint16 id;
    static char msg[60];
    ENTER_CRITICAL();
    id = GKI_GetExecutingTaskId();
    sprintf(msg, "%s: Out of Heap when allocating %d bytes\r\n",
            GKI_ModuleName(), xWantedSize);
    GKI_putstring(msg);
    ShowTaskSpace();
    EXIT_CRITICAL();
}



/*******************************************************************************
* Function         GKI_DeviceUp
* Description      Return true if device is initialized.
*******************************************************************************/
bool GKI_DeviceUp(void)
{
    BOOLEAN BTM_IsDeviceUp(void);
    return BTM_IsDeviceUp();
}



/*******************************************************************************
* Stack Overflow Hook
*******************************************************************************/
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName )
{
    static char msg[40];
    static u8 i;
    static char *Name;
    ENTER_CRITICAL();
    Name = "Unknown";
    for (i=0; i<MAX_MODULES; i++) {
        if (GKI_Module[i].TaskHandle == pxTask) {
            Name = GKI_Module[i].Name;
            break;
        }
    }
    sprintf(msg, "STACK OVERFLOW IN TASK %s\r\n", Name);
    GKI_putstring(msg);
    ShowTaskSpace();

    // Halt
    while (1);

    EXIT_CRITICAL();
}




/*******************************************************************************
* Function         GKI_InitSignals
* Description      Initialize Signals
*******************************************************************************/
void GKI_InitSignals(void)
{
    // Init Short Signal List
    GKI_Data.FreeShortSignalList = (tGKI_Signal*)&GKI_Data.ShortSignals[0];
    for (int i = 0; i < GKI_NO_OF_SHORT_SIGNALS; i++)
    {
        GKI_Data.ShortSignals[i].Head.SignalNumber  = GKI_INVALID_SIGNAL_NUMBER;
        GKI_Data.ShortSignals[i].Head.SenderTaskId  = GKI_INVALID_TID;
        GKI_Data.ShortSignals[i].Head.OwnerTaskId   = GKI_INVALID_TID;
        GKI_Data.ShortSignals[i].Head.pNextSignal   = (tGKI_Signal*)&GKI_Data.ShortSignals[i+1];
        GKI_Data.ShortSignals[i].Head.DataSize      = 0;
    }
    GKI_Data.ShortSignals[GKI_NO_OF_SHORT_SIGNALS-1].Head.pNextSignal = NULL;

    // Init Long Signal List
    GKI_Data.FreeLongSignalList = (tGKI_Signal*)&GKI_Data.LongSignals[0];
    for (int i = 0; i < GKI_NO_OF_LONG_SIGNALS; i++)
    {
        GKI_Data.LongSignals[i].Head.SignalNumber   = GKI_INVALID_SIGNAL_NUMBER;
        GKI_Data.LongSignals[i].Head.SenderTaskId   = GKI_INVALID_TID;
        GKI_Data.LongSignals[i].Head.OwnerTaskId    = GKI_INVALID_TID;
        GKI_Data.LongSignals[i].Head.pNextSignal    = (tGKI_Signal*)&GKI_Data.LongSignals[i+1];
        GKI_Data.LongSignals[i].Head.DataSize       = 0;
    }
    GKI_Data.LongSignals[GKI_NO_OF_LONG_SIGNALS-1].Head.pNextSignal = NULL;
}



/*******************************************************************************
* Function          GKI_AllocMemory
* Description       Allocate Memory
*******************************************************************************/
void *GKI_AllocMemory(size_t sz)
{
    return pvPortMalloc(sz);
}



/*******************************************************************************
* Function          GKI_ReleaseMemory
* Description       Free Memory
*******************************************************************************/
void GKI_ReleaseMemory(void *mem)
{
    vPortFree(mem);
}



/*******************************************************************************
* Function          GKI_EndTask
* Description       Delete Current Task
*******************************************************************************/
void GKI_EndTask(void)
{
    vTaskDelete(NULL);
}



/*******************************************************************************
* Function          GKI_enter_critical
* Description       Disable interrupts and return last interrupt state
*******************************************************************************/
tGKI_Critical GKI_enter_critical(void)
{
    tGKI_Critical cs;
    cs = GKI_get_interrupt_state();
    GKI_disable_interrupt();
    return cs;
}



/*******************************************************************************
* Function          GKI_exit_critical
* Description       Set interrupt state to cs
*******************************************************************************/
void GKI_exit_critical(tGKI_Critical cs)
{
    GKI_set_interrupt_state(cs);
}



/*******************************************************************************
* Function          GKI_GenerateSystemReset
* Description       Generate a system reset
*******************************************************************************/
void GKI_GenerateSystemReset(void)
{
#ifndef STACK_ONLY
    NVIC_GenerateSystemReset();
#endif
}



/*******************************************************************************
* Function          GKI_GetModuleNameFromId
* Description       Get the module name from the module ID
*******************************************************************************/
char * GKI_GetModuleNameFromId(u16 id)
{
    if (id==GKI_INVALID_TID)
        return "inv";
    else if (id>=MAX_MODULES)
        return "err";
    else
        return GKI_Module[id].Name;
}


/*******************************************************************************
* Function          GKI_putstring
* Description       Used for debugging
*******************************************************************************/
void GKI_putstring(char *msg)
{
#ifndef STACK_ONLY
    void SerialPutString(char *);
    ENTER_CRITICAL();
    SerialPutString(msg);
    EXIT_CRITICAL();
#endif
}



/*******************************************************************************
* Function          GKI_IS_ISR_MODE
* Description       Return true if in interrupt context
*******************************************************************************/
bool GKI_IS_ISR_MODE(void)
{
#ifdef STACK_ONLY
    return 0;
#else
    return __READ_IPSR();
#endif
}


/*******************************************************************************
* Function          UART_SetBaudrate
* Description       Set baudrate
*******************************************************************************/
void  UART_SetBaudrate(u16 u, u32 baudrate)
{
#ifndef STACK_ONLY
#ifdef __IAR_SYSTEMS_LIB__
    tTM_UartDev *pUart = &TM_UartDev[u];
    USART_TypeDef * UartDev = pUart->Device;

    u32 tmpreg = 0x00, apbclock = 0x00;
    u32 integerdivider = 0x00;
    u32 fractionaldivider = 0x00;
    u32 usartxbase = 0;
    RCC_ClocksTypeDef RCC_ClocksStatus;

    pUart->Baudrate = baudrate;

    RCC_GetClocksFreq(&RCC_ClocksStatus);
    if (usartxbase == USART1_BASE)
    {
        apbclock = RCC_ClocksStatus.PCLK2_Frequency;
    }
    else
    {
        apbclock = RCC_ClocksStatus.PCLK1_Frequency;
    }

    /* Determine the integer part */
    integerdivider = ((0x19 * apbclock) / (0x04 * baudrate));
    tmpreg = (integerdivider / 0x64) << 0x04;

    /* Determine the fractional part */
    fractionaldivider = integerdivider - (0x64 * (tmpreg >> 0x04));
    tmpreg |= ((((fractionaldivider * 0x10) + 0x32) / 0x64)) & ((u8)0x0F);

    /* Write to USART BRR */
    UartDev->BRR = (u16)tmpreg;
#endif
#endif
}


/*******************************************************************************
* Wait until all specified ready flags are set
*******************************************************************************/
void GKI_WaitUntilReady(u32 x)
{
    while ((GKI_Data.ReadyFlags & x) != x) {
        GKI_WaitMS(5);
    }
    NOP;
}


/*******************************************************************************
* Set ready flag(s)
*******************************************************************************/
void GKI_SetReady(u32 x)
{
    GKI_Data.ReadyFlags |= x;
    NOP;
}

/*******************************************************************************
* Return true if memory is valid
*******************************************************************************/
bool GKI_MemoryValid(void *mem)
{
    return ((u32)mem>=0x20000000 && (u32)mem<=0x2000FFFF);
}


/*******************************************************************************
* Used for io pins (not used for STACK_ONLY)
*******************************************************************************/
#ifdef STACK_ONLY
void  TM_SetPioAsOutput(u16 Pin) {}
void  TM_SetPioAsInput(u16 Pin) {}
void  TM_ResetPio(u16 Pin) {}
bool  TM_ReadPio(u16 Pin) { return 0; }
void  TM_SetPio(u16 Pin) {}
#endif


/*******************************************************************************
* Function         Non IAR intrinsics
* Description      Define if not an IAR compiler
*******************************************************************************/
#ifndef __IAR_SYSTEMS_LIB__
const char *__iar_Strchr(const char *_S, int _C)
{
      return (strchr(_S, _C));
}
const char *__iar_Strstr(const char *s1, const char *s2)
{
      return (strstr(s1, s2));
}
unsigned long __iar_Stoul(const char *_S, char **_Endptr, int _Base)
{
    return atoi(_S);
}
#endif





/*******************************************************************************
* Function         GKI_disable_interrupt
* Description      Disable interrupts
*******************************************************************************/
void GKI_disable_interrupt(void)
{
#ifdef IAR_ARM_CM3
    __disable_interrupt();
#endif
}


/*******************************************************************************
* Function         GKI_enable_interrupt
* Description      Enable interrupts
*******************************************************************************/
void GKI_enable_interrupt(void)
{
#ifdef IAR_ARM_CM3
    __enable_interrupt();
#endif
}



/*******************************************************************************
* Function         GKI_get_interrupt_state
* Description      Get interrupt system state
*******************************************************************************/
tGKI_Critical GKI_get_interrupt_state(void)
{
#ifdef IAR_ARM_CM3
    return __get_interrupt_state();
#else
    return 0;
#endif
}




/*******************************************************************************
* Function         UART_RxHandler
* Description      Callback for receiving UART Rx interrupts
* iSrc: GKI_IntSrc_IDLE - Character Idle Timeout
*       GKI_IntSrc_SWI  - Software Interrupt used to flush Rx buffers
*******************************************************************************/
void UART_RxHandler(u16 u, u16 iSrc)
{
    TM_UartMainRxHandler(u, iSrc);
}


/*******************************************************************************
* Function         RTC_IRQHandler
* Description      Callback timer interrupts
*******************************************************************************/
#ifdef IAR_ARM_CM3
void RTC_IRQHandler(void)
{
    extern void TM_TimeoutIsrRTS(void);
    TM_TimeoutIsrRTS();
}
#endif


/*******************************************************************************
* Function         UART_TxCompleteHandler
* Description      Callback for receiving UART Tx Complete interrupts
*******************************************************************************/
void UART_TxCompleteHandler(u16 u)
{
    TM_DmaSendComplete(u);
}





/*******************************************************************************
* Function         GKI_set_interrupt_state
* Description      Set interrupt system state
*******************************************************************************/
void GKI_set_interrupt_state(tGKI_Critical cs)
{
#ifdef IAR_ARM_CM3
    __set_interrupt_state(cs);
#endif
}


//-------------------------------------------------------------------------------
//          S T A C K   O N L Y   S E C T I O N
//-------------------------------------------------------------------------------
#ifdef STACK_ONLY
void RTC_SetAlarm(u32 AlarmValue) {}

bool  TM_HciReadyToSend(void)               {   return (0==GKI_io_ReadBit(IO_HCI_CTS)); }
void  TM_MainUartReceiveEnable(bool enb)    {   GKI_io_WriteBit(IO_MAIN_RTS,!enb);      }
void  TM_BTControllerWake(void)             {   GKI_io_WriteBit(IO_HCI_BT_WAKE,1);      }
void  TM_BTControllerSleep(void)            {   GKI_io_WriteBit(IO_HCI_BT_WAKE,0);      }
void  TM_IsUartRxNotEmpty(void *Uart) {}
void  TM_IsUartTxEmpty(void *Uart) {}
void  TM_HciReceiveEnable(bool enb)         {   GKI_io_WriteBit(IO_HCI_RTS,!enb);       }
void  TM_IsUartTxFull(void *Uart) {}
void  TM_IsUartTxHalfEmpty(void *Uart) {}
void  TM_IsUartRxTOIdle(void *Uart) {}
void  TM_SetUartChrTimeout(void *Uart, uint16 timeout) {}
void  TM_EnableMainUartTxInterrupt(void) {}
void  TM_DisableMainUartTxInterrupt(void) {}
bool  TM_GetHostWake(void)                  {   return GKI_io_ReadBit(IO_HCI_HOST_WAKE);}
//void  TM_usDelay(uint32 usDelay) {}
void  TM_ConnectLED_ON() {}
void  TM_ConnectLED_OFF() {}
void  TM_PowerAwakeLED_OFF() {}
void  TM_PowerAwakeLED_ON() {}


void TM_UartTxInit(tTM_UartType u, tIOCompleteCallback TxCallback) {}
void TM_UartHciRxInit(tTM_UartType u, tUartCompleteCallback RxCallBack) {}
void TM_UartMainRxInit(tTM_UartType u, tUartCompleteCallback RxCallback) {}
tIoStatus TM_UartRxAbort(tTM_UartType u, uint8** ppBuff, int* pBytesRcvd) { return 0; }
tIoStatus TM_UartRxGet(tTM_UartType u) { return 0; }

#endif



#endif // FREE_RTOS
//--------------------------------------------------------------
//