
#include "stdint.h"
#include "string.h"
#include "rtthread.h"
#include "board.h"
#include "debug.h"


typedef struct 
{
  uint8_t *membase;   // 内存池
  uint8_t memrdy;     // 内存管理是否就绪
  uint16_t *memmap;   // 内存管理状态表
  // 内存管理参数	   
  uint32_t memtblsize ;		// 内存表大小
  uint32_t memblksize;		// 内存分块大小
  uint32_t memsize    ;		// 内存总大小
  uint32_t used;
  void *mutex;
}mallco_dev;





#define SRAM_USER_SIZE (9*1024)
#define MEM_BLOCK_SIZE			  (32)
#define MEM_MAX_SIZE			    (((SRAM_USER_SIZE))*MEM_BLOCK_SIZE/(MEM_BLOCK_SIZE+2))  						    
#define MEM_ALLOC_TABLE_SIZE	((MEM_MAX_SIZE/MEM_BLOCK_SIZE)&(~3))
#define SRAM_USER_ADDR ((uint32_t)g_sram_mem)

//分配的内存都是双字对齐的
#define MEM_BASE ((uint8_t *)(SRAM_USER_ADDR+MEM_ALLOC_TABLE_SIZE*2))
#define MEMMAP_BASE ((uint16_t *)(SRAM_USER_ADDR))

static uint8_t g_sram_mem[SRAM_USER_SIZE];
//内存管理控制器
static mallco_dev g_self;




//内存管理初始化  
void mem_init(void)  
{  
  mallco_dev *self=&g_self;
  if(self->memrdy) return;
  
	self->memtblsize = MEM_ALLOC_TABLE_SIZE;
	self->memblksize = MEM_BLOCK_SIZE;
	self->memsize    = MEM_MAX_SIZE;
	self->membase=MEM_BASE;
	self->memmap=MEMMAP_BASE;
	
  memset(self->memmap, 0,self->memtblsize*2);
	memset(self->membase, 0,self->memsize);
  self->mutex=rt_mutex_create("mem",RT_IPC_FLAG_FIFO);
	self->memrdy=1;
} 
 


// 获取内存使用率
// 返回值:使用率(0~100)
int mem_perused(void)  
{   
  mallco_dev *self=&g_self;
  uint32_t used=0;  
  uint32_t i;  
  for(i=0;i<self->memtblsize;i++)  
  {  
    if(self->memmap[i])used++; 
  } 
  //return (used*100)/(self->memtblsize); 
  self->used=used*MEM_BLOCK_SIZE;
  // 改为实际使用的字节数
  return self->used;
}  







// 内存分配(内部调用)
// size:要分配的内存大小(字节)
// 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 
static uint32_t mem_malloc(uint32_t size)  
{  
  mallco_dev *self=&g_self;
  signed long offset=0;  
  uint16_t nmemb;
  uint16_t cmemb=0;
  uint32_t i;  
  uint32_t ret=0xffffffff;
  if(size==0)return ret;
  rt_mutex_take(self->mutex,RT_WAITING_FOREVER);
  nmemb=size/self->memblksize;
  if(size%self->memblksize)nmemb++;  
  for(offset=self->memtblsize-1;offset>=0;offset--)
  {     
    if(!self->memmap[offset])cmemb++;
    else cmemb=0;
    if(cmemb==nmemb)
    {
      for(i=0;i<nmemb;i++)
      {  
        self->memmap[offset+i]=nmemb;  
      }  
      ret= (offset*self->memblksize);
      break;
    }
  }  
  rt_mutex_release(self->mutex);
  return ret;
}

//释放内存(内部调用) 
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;  
static int mem_free(uint32_t offset)  
{  
  mallco_dev *self=&g_self;
  int i;
  int ret=1;
  rt_mutex_take(self->mutex,RT_WAITING_FOREVER);
  if(offset<self->memsize)
  {  
    int index=offset/self->memblksize;
    int nmemb=self->memmap[index];
    for(i=0;i<nmemb;i++)
    {  
      self->memmap[index+i]=0;  
    }  
    ret= 0;  
  }
  rt_mutex_release(self->mutex);
  return ret;
}  





void *malloc(uint32_t size)  
{  
  mallco_dev *self=&g_self;
  uint32_t offset;  
  int used=0;
	void *ret_addr=NULL;
	offset=mem_malloc(size); 
	if (offset!=0XFFFFFFFF)
	{
		ret_addr=(void*)((uint32_t)self->membase+offset);  
	}
  else{
    used=mem_perused();
    param_check(0);
  }
	return ret_addr;  
}  



static void self_free(void *ptr)  
{  
  mallco_dev *self=&g_self;
	uint32_t offset;  
	if(ptr==NULL)
	{
		return;
	}
	else
	{
		offset=(uint32_t)ptr-(uint32_t)self->membase;  
		mem_free(offset); 
	}
}


void *calloc(size_t nmemb, size_t size)
{
  void *p;
  p=malloc(nmemb*size);
  if(p) memset(p,0,size);
  return p;
}


void *realloc(void *p,size_t size)
{
  param_check(0);
  return NULL;
}


/*
void *malloc(size_t size)
{
  return rt_malloc_align(size,4);
}
void *calloc(size_t nmemb,size_t size)
{
  return rt_calloc(nmemb,size);
}
void *realloc(void *p,size_t size)
{
  return rt_realloc(p,size);
}
static void self_free(void *p)
{
  rt_free(p);
}

void mem_init(void)
{
}
int mem_perused(void)
{
  uint32_t used,total,max_used;
  rt_memory_info(&total,&used,&max_used);
  return used;
}


*/


#define MEM_TEMP_PTR_NUM  800
typedef void (*del_fun_def)(void *t);

typedef struct{
  void *temp_ptr[MEM_TEMP_PTR_NUM];
  void *del_ptr[MEM_TEMP_PTR_NUM];
  int used;
  uint32_t bitmap[(MEM_TEMP_PTR_NUM+31)/32];
  void *mutex;
}temp_def;
static temp_def g_tempptr;


// 在位图中找到一个0/1
static int bitmap_find(uint32_t *bitmap,int num,int bit)
{
  for(int i=0;i<num;i++)
  {
    if((bitmap[i/32]&(1<<(i%32)))==(bit<<(i%32)))
    {
      return i;
    }
  }
  return -1;
}
// 设置位图中指定位
static void bitmap_set(uint32_t *bitmap,int index)
{
  bitmap[index/32]|=1<<(index%32);
}
static void bitmap_clear(uint32_t *bitmap,int index)
{
  bitmap[index/32]&=~(1<<(index%32));
}
static int bitmap_get(uint32_t *bitmap,int index)
{
  return (bitmap[index/32]&(1<<(index%32)))==(1<<(index%32));
}
static void *tempptr_append(temp_def *t,void *p,void *del_fun)
{
  if(p==NULL) return p;
  void *ret=NULL;
  if(del_fun==0) del_fun=self_free;
  if(t->used<MEM_TEMP_PTR_NUM)
  {
    int index=bitmap_find(t->bitmap,MEM_TEMP_PTR_NUM,0);
    param_check(index>=0);
    t->temp_ptr[index]=p;
    t->del_ptr[index]=del_fun;
    bitmap_set(t->bitmap,index);
    ret= p;
    t->used++;
  }
  else{
    param_check(0);
  }
  if(ret==NULL) ((del_fun_def)del_fun)(p);
  return ret;
}

// 查询指针是否已存在
static int tempptr_find(temp_def *t,void *p)
{
  int index;
  for(int i=0;i<MEM_TEMP_PTR_NUM;i++)
  {
    if(bitmap_get(t->bitmap,i))
    {
      if(t->temp_ptr[i]==p)
      {
        return 1;
      }
    }
  }
  return 0;
}



static void tempptr_free(void)
{
  int index;
  void *p=NULL;
  del_fun_def del=NULL;
  temp_def *t=&g_tempptr;
  rt_mutex_take(t->mutex,RT_WAITING_FOREVER);
  if(index=bitmap_find(t->bitmap,MEM_TEMP_PTR_NUM,1),index>=0)
  {
    // DBG_LOG("%s:free tempptr",__func__);
    p=t->temp_ptr[index];
    t->temp_ptr[index]=0;
    del=(del_fun_def)t->del_ptr[index];
    bitmap_clear(t->bitmap,index);
    t->used--;
  }
  rt_mutex_release(t->mutex);
  if(del) del(p);
}


void tempptr_init(void)
{
  temp_def *t=&g_tempptr;
  t->mutex=rt_mutex_create("tempptr",RT_IPC_FLAG_FIFO);
  rt_thread_idle_sethook(tempptr_free);
}




// 申请临时内存,在任务结束后自动释放
void *tmalloc(uint32_t size)
{
  void *p;
  temp_def *t=&g_tempptr;
  p=malloc(size);
  rt_mutex_take(t->mutex,RT_WAITING_FOREVER);
  p=tempptr_append(&g_tempptr,p,NULL);
  rt_mutex_release(t->mutex);
  return p;
}

// 把指针添加为临时指针
void *tappend(void *p,void *del)
{
  temp_def *t=&g_tempptr;
  void *ret=NULL;
  if(p==NULL) return p;
  rt_mutex_take(t->mutex,RT_WAITING_FOREVER);
  {
    if(tempptr_find(t,p)==0)
    {
      ret= tempptr_append(t,p,del);
    }else{
      ret=p;
    }
  }
  rt_mutex_release(t->mutex);
  return ret;
}



// 释放内存，如果在临时表中则退出
void free(void *p)
{
  if(p==NULL) return;
  temp_def *t=&g_tempptr;
  int ret=0;
  rt_mutex_take(t->mutex,RT_WAITING_FOREVER);
  ret=tempptr_find(t,p);
  rt_mutex_release(t->mutex);
  if(ret){
    return;
  }else{
    self_free(p);
  }
}



