/**
 * \file   newlib_syscalls.c
 * \author Štefan Mišík
 * \date   Január, 2014
 * \brief  Prepojenie newlib a FreeRTOS-u
 *
 * \details
 * V tomto súbore sa nachádzajú implementácie funkcií prepájajúcich
 * newlib knižnicu s operačným systémom freeRTOS.
 *
 */

#include <stdlib.h>
#include <malloc.h>
#include <errno.h>
#include <sys/times.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <FreeRTOS.h>
#include <task.h>

/**
 * \defgroup	syscalls Newlib syscalls
 * \brief 		Modul obsahuje funkcie na prepojenie OS s knižnicou newlib
 *
 * Funkcie definované v tomto module sú tzv. 'syscall' funkmcie, ktoré slúžia
 * na prepojenie štandardnej C knižnice implementovanej v súbore knižníc newlib.
 * Knižnica newlib sa spolieha na implementáciu týchto funkcií tak, aby mohla
 * vykonávať operácie, pri ktorých interaguje s operačným systémom.
 */

/**
 * \addtogroup system
 */
/**\{*/

/**
 * \addtogroup syscalls
 */
/**\{*/




/**
 * \name    _exit
 * \brief   Ukončenie procesu
 *
 * Knižnica newlib používa volanie tejto funkcie na ukončenie, procesu, ktorý
 * o to požiada.
 *
 * \param 	[in] iExitCode Kód ukončenia procesu. Nepoužíva sa
 */
void _exit
	(
		int iExitCode
	)
{
	/* Ukončí volajúci proces */
	vTaskDelete( NULL );

	/* Sem by sa program nemal dostať */
	/* portDISABLE_INTERRUPTS(); */
	while(1)
	{

	}
}


/**
 * \name    _close
 * \brief   Zavretie súboru
 *
 * \param 	[in] iFile identifikátor súboru
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _close
	(
		int iFile
	)
{
	/* Zatiaľ nie je implementované */
	errno = ENOSYS;
	return -1;
}


/**
 * \name    _execve
 * \brief   Spustenie procesu
 *
 * \param 	[in] pszName 	Meno proesu
 * \param	[in] apszArgv 	Pole argumentov
 * \param	[in] apszEnv	Pole premenných prostredia
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _execve
	(
		char *pszName,
		char **apszArgv,
		char **apszEnv
	)
{
	/* Neimplementovaný stub */
	errno = ENOMEM;
	return -1;
}


/**
 * \name    _fork
 * \brief   Rozvetvenie procesu
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _fork
	(
		void
	)
{
	errno = EAGAIN;
	return -1;
}


/**
 * \name    _fstat
 * \brief   Stav otvoreného súboru
 *
 * \param 	[in]  iFile 	Deskriptor súboru
 * \param	[out] pstSt 	Stavová štruktúra
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _fstat
	(
		int iFile,
		struct stat *pstSt
	)
{
	pstSt->st_mode = S_IFCHR;
    return 0;
}


/**
 * \name    _getpid
 * \brief   Získanie identifikátoru procesu
 *
 * \retval	Identifikátor volajúceho procesu
 */
int _getpid
	(
		void
	)
{
	/* Identifikátor je vytvorený pretypovaním deskriptoru procesu */
	return (int)xTaskGetCurrentTaskHandle();
}


/**
 * \name    _isatty
 * \brief   Stream je smerovaný na terminál
 *
 * \param 	[in] iFile 	Deskriptor súboru
 *
 * \retval	0 Stream nie je nasmerovaný do terminálu
 * \retval	1 Stream je nasmerovaný do terminálu
 */
int _isatty
	(
		int iFile
	)
{
	return 1;
}

/**
 * \name    _kill
 * \brief   Pošli signál procesu
 *
 * \param 	[in] iPid 	Identifikátor procesu
 * \param	[in] iSig	Číslo signálu
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _kill
	(
		int iPid,
		int iSig
	)
{
	errno = EINVAL;
	return -1;
}


/**
 * \name    _link
 * \brief   Nastav nové meno pre existujúci súbor
 *
 * \param 	[in] pszOld	Staré meno
 * \param	[in] pszNew	Nové meno
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _link
	(
		char *pszOld,
		char *pszNew
	)
{
	errno = EMLINK;
	return -1;
}


/**
 * \name    _lseek
 * \brief   Nastav pozíciu v súbore
 *
 * \param 	[in] iFile	Deskriptor súboru
 * \param	[in] iPtr	Ukazateľ
 * \param	[in] iDir	Smer
 *
 * \retval	Nová pozícia kurzoru v otvorenom súbore
 */
int _lseek
	(
		int iFile,
		int iPtr,
		int iDir
	)
{
	return 0;
}


/**
 * \name    _open
 * \brief   Otvor súbor
 *
 * \param 	[in] pcszName	Názov súboru
 * \param	[in] iFlags		Flagy
 * \param	[in] iMode		Mód
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _open
	(
		const char 	*pcszName,
		int			iFlags,
		int			iMode
	)
{
	errno = ENOSYS;
	return -1;
}


/**
 * \name    _read
 * \brief   Čítaj zo súboru
 *
 * \param 	[in] iFile	Deskriptor súboru
 * \param	[in] pPtr	Ukazovateľ na buffer, ktorý obdrží prečítané dáta
 * \param	[in] iLen	Počet bajtov, ktoré sa majú prečítať
 *
 * \retval 	Počet prečítaných bajtov
 */
int _read
	(
		int 	iFile,
		char 	*pPtr,
		int		iLen
	)
{
	return 0;
}


/**
 * \name    _write
 * \brief   Zapíš do súboru
 *
 * \param 	[in] iFile	Deskriptor súboru
 * \param	[in] pPtr	Ukazovateľ na buffer, ktorý obdrží prečítané dáta
 * \param	[in] iLen	Počet bajtov, ktoré sa majú zapísať
 *
 * \retval 	Počet zapísaných bajtov
 */
int _write
	(
		int 	iFile,
		char 	*pPtr,
		int		iLen
	)
{
	return 0;
}


/**
 * \name    _stat
 * \brief   Stav súboru
 *
 * \param 	[in]  pcszFile	Názov súboru
 * \param	[out] pstSt 		Stavová štruktúra
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _stat
	(
		const char	*pcszFile,
		struct stat	*pstSt
	)
{
	pstSt->st_mode = S_IFCHR;
	return 0;
}


/**
 * \name    _times
 * \brief   Informácie o čase procesu
 *
 * \param 	[out] pstBuf	Štruktúra, ktorá obdrží časové informácie
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _times
	(
		struct tms *pstBuf
	)
{
	errno = ENOSYS;
	return -1;
}


/**
 * \name    _gettimeofday
 * \brief   Informácie o aktuálnom čase
 *
 * \param 	[out] pstTv	Štruktúra, ktorá obdrží časové informácie
 * \param 	[out] pstTz	Štruktúra, ktorá obdrží informácie o časovej zóne
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _gettimeofday
	(
		struct timeval 	*pstTv,
		struct timezone	*pstTz
	)
{
	return -1;
}

/**
 * \name    _unlink
 * \brief   Odstráň zápis o súbore v priečinku
 *
 * \param 	[in] pcszName	Názov súboru
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _unlink
	(
		const char *pcszName
	)
{
	errno = ENOENT;
	return -1;
}


/**
 * \name    _wait
 * \brief   Počkaj na dcérsky proces
 *
 * \param 	[out] piStatus	Status ukončnia procesu
 *
 * \retval	0 Úspech
 * \retval	Inak neúspech
 */
int _wait
	(
		int *piStatus
	)
{
	errno = ECHILD;
	return -1;
}


/**
 *  \brief      End of external ram
 *  \ingroup    syscalls
 */
#define END_OF_EXT_RAM  0x60100000

/**
 *  \brief Address of symbolu _emb1ram points to first byte of external memory
 *  unused by linker
 */
extern char _emb1ram;

/**
 * \name    _sbrk
 * \brief   Požiadavka na alokovanie pamäte
 *
 * Štandardná C knižnica volaním tejto funkcie žiada OS o pridelenie pamäte.
 * Implementácuia v navrhnutom riešení sa však nespolieha na operačný systém
 * freeRTOS pri prideľovaní pamäte, ale prideľuje pamäť z vopred definovanej
 * pamäťovej oblasti.
 *
 * \param 	[in] iIncr  Počet bajtov pamäťe, ktoré plikácia požaduje
 *
 * \retval	ukazateľ na blok alokovanej pamäte s veľkosťou minimálne \a iIncr
 * 			bajtov
 */
caddr_t _sbrk
	(
		int incr
	)
{
	caddr_t result;
	static caddr_t heap_end = &_emb1ram;

	if( incr + ((unsigned int)heap_end) < END_OF_EXT_RAM)
	{
	    result = heap_end;
	    heap_end += incr;
	}
	else
	{
	    errno = ENOMEM;
	    result = (caddr_t)-1;
	}

	/* Vráť ukazateľ na alokovaný blok pamäte */
	return result;
}


/**
 * \name    __malloc_lock
 * \brief   Uzamknutie zámku zabezpečujúceho haldu
 *
 * \param 	[in] reent Ukazateľ na aktuálnu \a _reent štruktúru
 */
void __malloc_lock
	(
		struct _reent *reent
	)
{
	/* Dočasne zakáž prepnutie kontextu */
	vTaskSuspendAll();
}


/**
 * \name    __malloc_unlock
 * \brief   Odomnknutie zámku zabezpečujúceho haldu
 *
 * \param 	[in] reent Ukazateľ na aktuálnu \a _reent štruktúru
 */
void __malloc_unlock
	(
		struct _reent *reent
	)
{
	/* Opätovne povoľ prepnutie kontextu */
	xTaskResumeAll();
}


/**
 * \name    __env_lock
 * \brief   Uzamknutie zámku zabezpečujúceho premenné prostredia
 *
 * \param 	[in] reent Ukazateľ na aktuálnu \a _reent štruktúru
 */
void __env_lock
	(
		struct _reent *reent
	)
{
	/* Dočasne zakáž prepnutie kontextu */
	vTaskSuspendAll();
}


/**
 * \name    __env_unlock
 * \brief   Odomnknutie zámku zabezpečujúceho premenné prostredia
 *
 * \param 	[in] reent Ukazateľ na aktuálnu \a _reent štruktúru
 */
void __env_unlock
	(
		struct _reent *reent
	)
{
	/* Opätovne povoľ prepnutie kontextu */
	xTaskResumeAll();
}


/**
 * \name    __tz_lock
 * \brief   Uzamknutie zámku zabezpečujúceho premenné časového pásma
 *
 * \param 	[in] reent Ukazateľ na aktuálnu \a _reent štruktúru
 */
void __tz_lock
	(
		struct _reent *reent
	)
{
	/* Dočasne zakáž prepnutie kontextu */
	vTaskSuspendAll();
}


/**
 * \name    __tz_unlock
 * \brief   Odomnknutie zámku zabezpečujúceho premenné časového pásma
 *
 * \param 	[in] reent Ukazateľ na aktuálnu \a _reent štruktúru
 */
void __tz_unlock
	(
		struct _reent *reent
	)
{
	/* Opätovne povoľ prepnutie kontextu */
	xTaskResumeAll();
}

/**\}*/
/**\}*/
/**\}*/


