/*******************************************************************************/

/* lwIP includes. */
#include "debug.h"
#include "def.h"
#include "sys.h"
#include "mem.h"
#include "cc.h"
#include "string.h"

#include "arch/sys_arch.h"

/************************************宏定义************************************/

#define SYS_ARCH_GLOBALS

/*********************************普通变量定义*********************************/

#define LWIP_ARCH_TICK_PER_MS		1000/OS_CFG_TICK_RATE_HZ

/*********************************任务变量定义*********************************/

static OS_MEM StackMem;											//定义内存分区（内存池）

const void * const pvNullPointer = (mem_ptr_t*)0xffffffff;		//消息空指针
#pragma pack(4)
CPU_STK       LwIP_Task_Stk[LWIP_TASK_MAX*LWIP_STK_SIZE];		//LwIP线程堆栈空间
#pragma pack(4)
CPU_INT08U    LwIP_task_priopity_stask[LWIP_TASK_MAX];
OS_TCB        LwIP_task_TCB[LWIP_TASK_MAX];

/*******************************************************************************
* 函数名称:	 void sys_init(void)
* 函数说明： 初始化网络协议栈系统所需要的内存块,此函数应该被先调用
* 输入参数： 无
* 返回参数： 无
*******************************************************************************/
void sys_init(void)
{
	OS_ERR ucErr;
	memset(LwIP_task_priopity_stask,0,sizeof(LwIP_task_priopity_stask));
	/* init mem used by sys_mbox_t, use ucosII functions */
	OSMemCreate(&StackMem,"LWIP TASK STK",(void*)LwIP_Task_Stk,LWIP_TASK_MAX,LWIP_STK_SIZE*sizeof(CPU_STK),&ucErr);
	LWIP_ASSERT( "sys_init: failed OSMemCreate STK", ucErr == OS_ERR_NONE );
}

/*******************************************************************************
* 函数名称:	 err_t sys_sem_new(sys_sem_t *sem, u8_t count)
* 函数说明： 创建信号量
* 输入参数： 信号量指针和初始值
* 返回参数： 无
*******************************************************************************/
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{
	OS_ERR	ucErr;
	OSSemCreate(sem,"LWIP Sem",count,&ucErr);
	if(ucErr != OS_ERR_NONE )
	{
		LWIP_ASSERT("OSSemCreate ",ucErr == OS_ERR_NONE );
		return -1;
	}
	return 0;
}

/*******************************************************************************
* 函数名称:	 void sys_sem_signal(sys_sem_t *sem)
* 函数说明： 发送信号量
* 输入参数： 信号量指针
* 返回参数： 无
*******************************************************************************/
void sys_sem_signal(sys_sem_t *sem)
{
	OS_ERR	ucErr;  
	OSSemPost(sem,OS_OPT_POST_ALL,&ucErr);
	LWIP_ASSERT("OSSemPost ",ucErr == OS_ERR_NONE );  
}

/*******************************************************************************
* 函数名称:	 void sys_sem_free(sys_sem_t *sem)
* 函数说明： 释放信号量
* 输入参数： 信号量指针 
* 返回参数： 无
*******************************************************************************/
void sys_sem_free(sys_sem_t *sem)
{
	OS_ERR	ucErr;
    OSSemDel(sem, OS_OPT_DEL_ALWAYS, &ucErr );
    LWIP_ASSERT( "OSSemDel ", ucErr == OS_ERR_NONE );
}

/*******************************************************************************
* 函数名称:	 int sys_sem_valid(sys_sem_t *sem)
* 函数说明： 判断信号量是有有效
* 输入参数： 信号量指针 
* 返回参数： 无
*******************************************************************************/
int sys_sem_valid(sys_sem_t *sem)
{
	if(sem->NamePtr)
		return (strcmp(sem->NamePtr,"?SEM"))? 1:0;
	else
		return 0;
}

/*******************************************************************************
* 函数名称:	 void sys_sem_set_invalid(sys_sem_t *sem)
* 函数说明： 将信号量置为无效
* 输入参数： 信号量指针 
* 返回参数： 无
*******************************************************************************/
void sys_sem_set_invalid(sys_sem_t *sem)
{
	if(sys_sem_valid(sem))
	{
		sys_sem_free(sem);
	}
}

/*******************************************************************************
* 函数名称:	 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
* 函数说明： 等待信号量
* 输入参数： 信号量指针，等待超时时间
* 返回参数： 返回等待时间
*******************************************************************************/
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
	OS_ERR	ucErr;
	CPU_TS        ucos_timeout;
	CPU_TS        in_timeout = timeout/LWIP_ARCH_TICK_PER_MS;
	if(timeout && in_timeout == 0)
		in_timeout = 1;  
	OSSemPend (sem,in_timeout,OS_OPT_PEND_BLOCKING,&ucos_timeout,&ucErr);
    /*  only when timeout! */
	if(ucErr == OS_ERR_TIMEOUT)
		ucos_timeout = SYS_ARCH_TIMEOUT;	
	return ucos_timeout;
}

/*******************************************************************************
* 函数名称:	 err_t sys_mbox_new( sys_mbox_t *mbox,int size)
* 函数说明： 创建一个新的消息邮箱
* 输入参数： 邮箱指针，邮箱大小
* 返回参数： 无
*******************************************************************************/
err_t sys_mbox_new( sys_mbox_t *mbox,int size)
{
    OS_ERR       ucErr;
      
	OSQCreate(mbox,"LWIP quiue", size, &ucErr); 
	LWIP_ASSERT( "OSQCreate ", ucErr == OS_ERR_NONE );
  
	if( ucErr == OS_ERR_NONE)
	{ 
		return 0; 
	}
	return -1;
}

/*******************************************************************************
* 函数名称:	 void sys_mbox_free(sys_mbox_t *mbox)
* 函数说明： 释放消息邮箱
* 输入参数： 邮箱指针
* 返回参数： 无
*******************************************************************************/
void sys_mbox_free(sys_mbox_t *mbox)
{
    OS_ERR     ucErr;
    LWIP_ASSERT( "sys_mbox_free ", mbox != SYS_MBOX_NULL );      
        
    OSQFlush(mbox,& ucErr);
    
    OSQDel(mbox, OS_OPT_DEL_ALWAYS, &ucErr);
    LWIP_ASSERT( "OSQDel ", ucErr == OS_ERR_NONE );
}

/*******************************************************************************
* 函数名称:	 void sys_mbox_post(sys_mbox_t *mbox, void *msg)
* 函数说明： 发送消息到消息邮箱
* 输入参数： 邮箱指针，消息指针
* 返回参数： 无
*******************************************************************************/
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
	OS_ERR     ucErr;
	CPU_INT08U  i=0;
	
	if( msg == NULL ) msg = (void*)&pvNullPointer;
	
	while(i<10)						//尝试发送10次
	{
		OSQPost(mbox, msg, 0, OS_OPT_POST_ALL, &ucErr);
		
		if(ucErr == OS_ERR_NONE)
			break;
		i++;
		OSTimeDly(5,OS_OPT_TIME_DLY,&ucErr);
	}
	LWIP_ASSERT( "sys_mbox_post error!\n", i !=10 );  
}

/*******************************************************************************
* 函数名称:	 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
* 函数说明： 尝试发送消息到消息邮箱，不保证发送成功
* 输入参数： 邮箱指针，消息指针
* 返回参数： 无
*******************************************************************************/
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
    OS_ERR     ucErr;
	if(msg == NULL ) msg = (void*)&pvNullPointer;
	OSQPost(mbox, msg,0,OS_OPT_POST_ALL,&ucErr);
	if(ucErr != OS_ERR_NONE)
	{
		return ERR_MEM;
	}
	return ERR_OK;
}

/*******************************************************************************
* 函数名称:	 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
* 函数说明： 从消息邮箱获取消息
* 输入参数： 邮箱指针	消息指针
* 返回参数： 无
*******************************************************************************/
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
	OS_ERR	ucErr;
	OS_MSG_SIZE   msg_size;
	CPU_TS        ucos_timeout;
	CPU_TS        in_timeout = timeout/LWIP_ARCH_TICK_PER_MS;
	if(timeout && in_timeout == 0)
		in_timeout = 1;
	*msg  = OSQPend (mbox,in_timeout,OS_OPT_PEND_BLOCKING,&msg_size,&ucos_timeout,&ucErr);

	if ( ucErr == OS_ERR_TIMEOUT )
		ucos_timeout = SYS_ARCH_TIMEOUT;
	return ucos_timeout;
}

/*******************************************************************************
* 函数名称:	 int sys_mbox_valid(sys_mbox_t *mbox)
* 函数说明： 获取消息邮箱的状态信息，判断消息邮箱是否有可用空间
* 输入参数： 邮箱指针 
* 返回参数： 返回1有效；0无效
*******************************************************************************/
int sys_mbox_valid(sys_mbox_t *mbox)
{
	if(mbox->NamePtr)  
		return (strcmp(mbox->NamePtr,"?Q"))? 1:0;
	else
		return 0;
}

/*******************************************************************************
* 函数名称:	 void sys_mbox_set_invalid(sys_mbox_t *mbox)
* 函数说明： 将消息邮箱置为无效
* 输入参数： 邮箱指针 
* 返回参数： 无
*******************************************************************************/
void sys_mbox_set_invalid(sys_mbox_t *mbox)
{
	if(sys_mbox_valid(mbox))
	{
		sys_mbox_free(mbox);	
	}
}

/*******************************************************************************
* 函数名称:	 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
* 函数说明： 启动一个由函数指针thread指定的命名为"name"的新线程，arg 将作为参数传递给thread()函数，
			 prio指定这个新线程的优先级，"stacksize"参数为该线程所需堆栈的大小。
* 输入参数： 
* 返回参数： 创建新线程状态
*******************************************************************************/
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
    int i;
	int tsk_prio;
	CPU_STK * task_stk = (CPU_STK * )0;
	CPU_INT08U  ubPrio = LWIP_TASK_START_PRIO;
    OS_ERR      ucErr;
    arg = arg;
     
    if(prio)
	{
		ubPrio +=(prio-1);
		for(i=0; i<LWIP_TASK_MAX; ++i)
			if(LwIP_task_priopity_stask[i] == ubPrio)
				break;
		if(i == LWIP_TASK_MAX)
		{
			for(i=0; i<LWIP_TASK_MAX; ++i)
				if(LwIP_task_priopity_stask[i]==0)
				{
					LwIP_task_priopity_stask[i] = ubPrio;
					break;
				}
        if(i == LWIP_TASK_MAX)
		{
			LWIP_ASSERT( "sys_thread_new: there is no space for priority", 0 );
			return (-1);
        }        
		}
		else
			prio = 0;
    }
  /* Search for a suitable priority */     
    if(!prio)
	{
		ubPrio = LWIP_TASK_START_PRIO;
		while(ubPrio < (LWIP_TASK_START_PRIO+LWIP_TASK_MAX))
		{ 
			for(i=0; i<LWIP_TASK_MAX; ++i)
				if(LwIP_task_priopity_stask[i] == ubPrio)
				{
					++ubPrio;
					break;
				}
			if(i == LWIP_TASK_MAX)
				break;
		}
		if(ubPrio < (LWIP_TASK_START_PRIO+LWIP_TASK_MAX))
			for(i=0; i<LWIP_TASK_MAX; ++i)
			if(LwIP_task_priopity_stask[i]==0)
			{
				LwIP_task_priopity_stask[i] = ubPrio;
				break;
			}
		if(ubPrio >= (LWIP_TASK_START_PRIO+LWIP_TASK_MAX) || i == LWIP_TASK_MAX)
		{
			LWIP_ASSERT( "sys_thread_new: there is no free priority", 0 );
			return (-1);
		}
	}
    if(stacksize > LWIP_STK_SIZE || !stacksize)   
        stacksize = LWIP_STK_SIZE;
	/* get Stack from pool */
    task_stk = OSMemGet( &StackMem, &ucErr );
    if(ucErr != OS_ERR_NONE)
	{
		LWIP_ASSERT( "sys_thread_new: impossible to get a stack", 0 );
		return (-1);
    } 
    tsk_prio = ubPrio-LWIP_TASK_START_PRIO;
    OSTaskCreate(&LwIP_task_TCB[tsk_prio],
                 (CPU_CHAR   *)name,
                 (OS_TASK_PTR )thread, 
                 (void       *)0,
                 (OS_PRIO     )ubPrio,
                 (CPU_STK    *)&task_stk[0],
                 (CPU_STK_SIZE)stacksize/10,
                 (CPU_STK_SIZE)stacksize,
                 (OS_MSG_QTY  )0,
                 (OS_TICK     )0,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&ucErr);    
    
    return ubPrio;
}

/***********************************FILE END***********************************/

