/*
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 *
 * Author: Adam Dunkels <adam@sics.se>
 *
 */


/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "arch/sys_arch.h"
#include "stdint.h"

#define LWIP_ARCH_TICK_PER_MS       (1000/OS_TICKS_PER_SEC)

uint32_t systick_timer = 0;




u32_t sys_jiffies(void)
{
	return systick_timer;
}

void systick_add(uint32_t tms)
{
	systick_timer += tms;
}

void systick_delayms(uint32_t tms)
{
	uint32_t tmp = systick_timer;

	while((systick_timer - tmp) < tms) {;}
}

u32_t sys_now(void)
{
  return sys_jiffies();
}


//void sys_msleep(u32_t ms)
//{
//	ms /= LWIP_ARCH_TICK_PER_MS;
//	if(!ms) ms = 1;
//	OSTimeDly(ms);
//}


//////////////////////////////////sem///////////////////////////////////////
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{
	*sem = OSSemCreate(count);

	if(*sem != NULL) return ERR_OK;
	else             return ERR_MEM;
}

void sys_sem_free(sys_sem_t *sem)
{
	INT8U err;
	
	OSSemDel(*sem, OS_DEL_ALWAYS, &err);
	
	*sem = SYS_SEM_NULL;
}

void sys_sem_signal(sys_sem_t *sem)
{
	OSSemPost(*sem);
}


u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
	u32_t wait_t;
	u32_t start_t, end_t;
	INT8U err;
	
	if(timeout != 0)
	{
		wait_t = timeout / LWIP_ARCH_TICK_PER_MS;
		if(!wait_t) wait_t = 1;
	}
	else wait_t = 0;
	
	start_t = sys_now();
	OSSemPend(*sem, wait_t, &err);
	end_t = sys_now();
	
	if(err == OS_ERR_NONE)
	{
		if(start_t <= end_t) end_t = (end_t -start_t);
		else                 end_t = (0xffffffff - start_t) + end_t + 1;
		return end_t;
	}
	else  return SYS_ARCH_TIMEOUT;
}

int sys_sem_valid(sys_sem_t *sem)
{
	if(*sem != SYS_SEM_NULL) return 1;
	else                     return 0;
}

void sys_sem_set_invalid(sys_sem_t *sem)
{
	*sem = SYS_SEM_NULL;
}


////////////////////////////////////////////////////////////////////////////////
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
	if(size > MAX_QUEUE_ENTRIES) size = MAX_QUEUE_ENTRIES;

	mbox->mboxQsq = OSQCreate(&mbox->msgBuffer[0], size);
	
	if(mbox->mboxQsq != NULL) return ERR_OK;
	else                      return ERR_MEM;
}

void sys_mbox_free(sys_mbox_t *mbox)
{
	INT8U err;
	
	OSQFlush(mbox->mboxQsq);
	OSQDel(mbox->mboxQsq, OS_DEL_ALWAYS, &err);
	
	mbox->mboxQsq = NULL;
}


void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
	INT8U i;
	
	for(i=0; i<10; i++)
	{
		if(OSQPost(mbox->mboxQsq, msg) == OS_ERR_NONE) break;
		OSTimeDly(5);
	}
}

err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
	if(OSQPost(mbox->mboxQsq, msg) == OS_ERR_NONE) return ERR_OK;
	else                                           return ERR_MEM;
}


u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
	u32_t ticks, start_t, end_t;
	void *temp;
	INT8U err;
	
	if(timeout != 0)
	{
		ticks = timeout / LWIP_ARCH_TICK_PER_MS;
		if(!ticks) ticks = 1;
	}
	else ticks = 0;

	start_t = sys_now();
	temp = OSQPend(mbox->mboxQsq, ticks, &err);
	end_t = sys_now();
	if(err == OS_ERR_NONE)
	{
		*msg = temp;
	  if(start_t <= end_t) timeout = end_t - start_t;
		else                 timeout = 0xffffffff - start_t + end_t + 1;
	}
	else 
	{
		timeout = SYS_ARCH_TIMEOUT;
		*msg = NULL;
	}
	
	return timeout;
}

u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
	INT8U err;
	void *temp;
	
	temp = OSQPend(mbox->mboxQsq, 1, &err);
	if(err == OS_ERR_NONE) 
	{
		*msg = temp;
		return 0;
	}
	else 
	{
		*msg = NULL;
		return SYS_ARCH_TIMEOUT;
	}
}

int sys_mbox_valid(sys_mbox_t *mbox)
{
	if(mbox->mboxQsq != SYS_MBOX_NULL) return 1;
	else                               return 0;
}	

void sys_mbox_set_invalid(sys_mbox_t *mbox)
{
	mbox->mboxQsq = SYS_MBOX_NULL;
}


//////////////////////////////////////////////////////////////
void sys_init(void)
{
	

}

static OS_STK tcpipThreadStack[TCPIP_THREAD_STACKSIZE];

sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
	INT8U err;

	err = OSTaskCreate(thread, arg, &tcpipThreadStack[stacksize-1], prio);
	if(err == OS_ERR_NONE) return prio;
	else                   return 0;
}






