
/**
@file shell_mem.c
@brief This template covers Three topics:\n
*/

/********************************************************************************************
Debug Switch Definition Section
********************************************************************************************/


/********************************************************************************************
Include File Section
********************************************************************************************/
#include "string.h"

#include "shell_mem.h"

/********************************************************************************************
Macro Definition Section
********************************************************************************************/

/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
SHELL_STATUS xShellMemInit(SHELL_MEM_CB *memcb, uint8_t *pmem, uint16_t maxcnt,\
                             uint32_t blksize, MEM_BIT_MAP_TYPE *bitmap, uint32_t szbitmap);
void * pvShellMemGet(SHELL_MEM_CB *memcb, SHELL_STATUS * rslt);
SHELL_STATUS xShellMemPut(SHELL_MEM_CB *memcb,  void *pmem);
uint8_t * pucShellMemGetIndex(SHELL_MEM_CB *memcb, uint32_t index);

/********************************************************************************************
Const Global Variable Definition Section
********************************************************************************************/


/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/


/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/


/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/

/********************************************************************************************
Function Definition Section
********************************************************************************************/

/**
 * DEBUGFS_MemInit
 * Author qiuxf
 * @param memcb
 * @param maxcnt
 * @param pmem
 * @param blksize
 * @return status
 */
SHELL_STATUS xShellMemInit(SHELL_MEM_CB *memcb, uint8_t *pmem, uint16_t maxcnt,\
                             uint32_t blksize, MEM_BIT_MAP_TYPE *bitmap, uint32_t szbitmap)
{
    SHELL_STATUS ret = PROC_SUCESS;

    if(MEM_BIT_MAP_WIDTH * szbitmap != maxcnt)
    {
        ret = PROC_INIT_FAIL;
    }
    else
    {
        memcb->lock = UNLOCK;
        memcb->pMem = pmem;
        memcb->MemMaxCnt = maxcnt;
        memcb->MemUnused = maxcnt;
        memcb->pMemBitmap = bitmap;
        memcb->MemBitmapLen = szbitmap;
        memcb->MemBlkSize = blksize;
    }
    return ret;
}

/**
 * DEBUGFS_MemGet
 * Author qiuxf
 * @param memcb
 * @return status
 */
static inline void vShellSpinGetLock(spinlock_t *lock)
{
   while(*lock != UNLOCK)
   {
       ;
       break;
   }
    *lock = LOCK;
    return;
}

static inline void vShellSpinSetLock(spinlock_t *lock)
{
    *lock = UNLOCK;
}
void * pvShellMemGet(SHELL_MEM_CB *memcb, SHELL_STATUS * rslt)
{
    void *ptmp = SAF_NULL;

    if(0 == memcb->MemUnused)
    {
        *rslt = PROC_NO_MEM;
    }
    else
    {
        uint32_t i  = 0;
        uint32_t j = 0;
        uint32_t blkidx = 0;
        vShellSpinGetLock(&memcb->lock);
        for(i = 0; i < memcb->MemBitmapLen; i++)
        {
            if(MEM_MAP_NO != memcb->pMemBitmap[i])      /*have unused block*/
            {
            	break;
            }
            else
            {
                ; /*continue*/
            }
        }

        for(j = 0; j < MEM_BIT_MAP_WIDTH; j++)
		{
			if(0 == ((memcb->pMemBitmap[i] >> j) & 1))
			{
				break;  /*find first unused block*/
			}
			else
			{
				; /*continue*/
			}
		}
        /*get unused block*/
        blkidx = MEM_BIT_MAP_WIDTH * i + j;
        ptmp = memcb->pMem + memcb->MemBlkSize * blkidx;
        /*clear mem*/
        memset(ptmp, 0, memcb->MemBlkSize);
        /*set flag*/
        memcb->pMemBitmap[i] |= (1 << j);
        memcb->MemUnused--;
        vShellSpinSetLock(&memcb->lock);
    }
    return ptmp;
}

/**
 * DEBUGFS_MemPut
 * Author qiuxf
 * @param memcb
 * @param pmem
 * @return status
 */
SHELL_STATUS xShellMemPut(SHELL_MEM_CB *memcb,  void *pmem)
{
    SHELL_STATUS ret = PROC_SUCESS;

    if(memcb->MemUnused == memcb->MemMaxCnt)
    {
        ret = PROC_NO_MEM_USED;
    }
    else
    {
        /*caluc offset*/
        uint32_t offset = (uint8_t *)pmem - memcb->pMem;
        uint32_t blkindex = 0;

        vShellSpinGetLock(&memcb->lock);
        if(offset < (memcb->MemBlkSize * memcb->MemMaxCnt))
        {
            if(0 == offset % memcb->MemBlkSize)
            {
                blkindex = offset / memcb->MemBlkSize;
                /*set map,and counter*/
                memcb->pMemBitmap[blkindex/MEM_BIT_MAP_WIDTH] &= ~(1 << (blkindex % MEM_BIT_MAP_WIDTH));
                memcb->MemUnused++;
            }
            else
            {
                ret = PROC_INVALUD_ALIGN;
            }
        }
        else
        {
            ret = PROC_INVALUD_MEM;
        }
        vShellSpinSetLock(&memcb->lock);
    }
    return ret;
}

/**
 * Shell_GetIndex
 * Author qiuxf
 * @param memcb
 * @param pmem
 * @return status
 */
uint8_t * pucShellMemGetIndex(SHELL_MEM_CB *memcb, uint32_t index)
{
    uint8_t *ptmp = SAF_NULL;

    if(index < memcb->MemMaxCnt)
    {
        uint8_t flag = 0;
        flag = (memcb->pMemBitmap[index / MEM_BIT_MAP_WIDTH] >> (index % MEM_BIT_MAP_WIDTH)) & 1;
        if(0 != flag)
        {
            ptmp = (uint8_t *)(memcb->pMemBitmap + index * memcb->MemBlkSize);
        }
        else
        {
            ;
        }
    }
    else
    {
        ;
    }

    return ptmp;
}
