/**
 * @file	OSAL.h
 * @brief	This file defines the OSAL class.
 * @date	19.12.2012
 * @author	baetz
 */

#ifndef OSAL_H_
#define OSAL_H_

#include <framework/returnvalues/HasReturnvaluesIF.h>

#define RTEMS_API 1

#ifndef API
#error Please specify Operating System API. Supported: API=RTEMS_API
#elif API == RTEMS_API
#include <rtems/endian.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <stdint.h>

//include RMAP

#define opus_main 				Init2
#define opus_main_arguments		rtems_task_argument

//Typedefs for RTEMS:	//TODO: these are global, shouldn't they have some prefix?
/**
 * A typedef to pass options to RTEMS elements.
 */
typedef rtems_option Option_t;
/**
 * A typedef to pass attributes to RTEMS elements.
 */
typedef rtems_attribute Attribute_t;
/**
 * A typedef for RTEMS task modes.
 */
typedef rtems_mode OpusMode_t;
/**
 * A typedef for time intervals. In clock ticks.
 */
typedef rtems_interval Interval_t;
typedef rtems_time_of_day TimeOfDay_t;
typedef rtems_id TaskId_t;
typedef rtems_id PeriodId_t;
typedef rtems_id MutexId_t;
typedef rtems_id MessageQueueId_t;
typedef rtems_name Name_t;

typedef rtems_task_argument TaskArgument_t;
typedef rtems_task_entry TaskEntry_t;
typedef rtems_task TaskReturn_t;
typedef rtems_task_priority TaskPriority_t;
typedef rtems_isr_entry IsrHandler_t;
typedef rtems_isr IsrReturn_t;
typedef rtems_vector_number InterruptNumber_t;

/**
 * This class contains encapsulates all System Calls to the Operating System.
 * It is currently tailored to the RTEMS Operating system, but should in general
 * support different OS.
 * For more detailed information on the Operating System calls, please refer to the
 * RTEMS documentation at www.rtems.org .
 */
class OSAL: public HasReturnvaluesIF {
private:
	/**
	 * A method to convert an OS-specific return code to the frameworks return value concept.
	 * @param inValue The return code coming from the OS.
	 * @return The converted return value.
	 */
	static ReturnValue_t convertReturnCode(uint8_t inValue);
public:

	static const uint8_t INTERFACE_ID = OPERATING_SYSTEM_ABSTRACTION;
	//Interrupts:
	static const uint32_t INTERRUPT_MASK_REGISTER_ADDRESS = 0x80000240;
	//API Status codes:
	static const ReturnValue_t SUCCESSFUL = RTEMS_SUCCESSFUL;
	static const ReturnValue_t TASK_EXITTED =
			MAKE_RETURN_CODE( RTEMS_TASK_EXITTED );
	static const ReturnValue_t MP_NOT_CONFIGURED =
			MAKE_RETURN_CODE( RTEMS_MP_NOT_CONFIGURED );
	static const ReturnValue_t INVALID_NAME =
			MAKE_RETURN_CODE( RTEMS_INVALID_NAME );
	static const ReturnValue_t INVALID_ID = MAKE_RETURN_CODE( RTEMS_INVALID_ID );
	static const ReturnValue_t TOO_MANY = MAKE_RETURN_CODE( RTEMS_TOO_MANY );
	static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE( RTEMS_TIMEOUT );
	static const ReturnValue_t OBJECT_WAS_DELETED =
			MAKE_RETURN_CODE( RTEMS_OBJECT_WAS_DELETED );
	static const ReturnValue_t INVALID_SIZE =
			MAKE_RETURN_CODE( RTEMS_INVALID_SIZE );
	static const ReturnValue_t INVALID_ADDRESS =
			MAKE_RETURN_CODE( RTEMS_INVALID_ADDRESS );
	static const ReturnValue_t INVALID_NUMBER =
			MAKE_RETURN_CODE( RTEMS_INVALID_NUMBER );
	static const ReturnValue_t NOT_DEFINED =
			MAKE_RETURN_CODE( RTEMS_NOT_DEFINED );
	static const ReturnValue_t RESOURCE_IN_USE =
			MAKE_RETURN_CODE( RTEMS_RESOURCE_IN_USE );
	static const ReturnValue_t UNSATISFIED =
			MAKE_RETURN_CODE( RTEMS_UNSATISFIED );
	static const ReturnValue_t QUEUE_EMPTY =
			MAKE_RETURN_CODE( RTEMS_UNSATISFIED );
	static const ReturnValue_t INCORRECT_STATE =
			MAKE_RETURN_CODE( RTEMS_INCORRECT_STATE );
	static const ReturnValue_t ALREADY_SUSPENDED =
			MAKE_RETURN_CODE( RTEMS_ALREADY_SUSPENDED );
	static const ReturnValue_t ILLEGAL_ON_SELF =
			MAKE_RETURN_CODE( RTEMS_ILLEGAL_ON_SELF );
	static const ReturnValue_t ILLEGAL_ON_REMOTE_OBJECT =
			MAKE_RETURN_CODE( RTEMS_ILLEGAL_ON_REMOTE_OBJECT );
	static const ReturnValue_t CALLED_FROM_ISR =
			MAKE_RETURN_CODE( RTEMS_CALLED_FROM_ISR );
	static const ReturnValue_t INVALID_PRIORITY =
			MAKE_RETURN_CODE( RTEMS_INVALID_PRIORITY );
	static const ReturnValue_t INVALID_CLOCK =
			MAKE_RETURN_CODE( RTEMS_INVALID_CLOCK );
	static const ReturnValue_t INVALID_NODE =
			MAKE_RETURN_CODE( RTEMS_INVALID_NODE );
	static const ReturnValue_t NOT_CONFIGURED =
			MAKE_RETURN_CODE( RTEMS_NOT_CONFIGURED );
	static const ReturnValue_t NOT_OWNER_OF_RESOURCE =
			MAKE_RETURN_CODE( RTEMS_NOT_OWNER_OF_RESOURCE );
	static const ReturnValue_t NOT_IMPLEMENTED =
			MAKE_RETURN_CODE( RTEMS_NOT_IMPLEMENTED );
	static const ReturnValue_t INTERNAL_ERROR =
			MAKE_RETURN_CODE( RTEMS_INTERNAL_ERROR );
	static const ReturnValue_t NO_MEMORY = MAKE_RETURN_CODE( RTEMS_NO_MEMORY );
	static const ReturnValue_t IO_ERROR = MAKE_RETURN_CODE( RTEMS_IO_ERROR );
	//API options:
	static const Option_t DEFAULT_OPTIONS = RTEMS_DEFAULT_OPTIONS;
	static const Option_t WAIT = RTEMS_WAIT;
	static const Option_t NO_WAIT = RTEMS_NO_WAIT;
	static const Option_t EVENT_ALL = RTEMS_EVENT_ALL;
	static const Option_t EVENT_ANY = RTEMS_EVENT_ANY;
	//API Attributes:
	static const Attribute_t DEFAULT_ATTRIBUTES = RTEMS_DEFAULT_ATTRIBUTES;
	static const Attribute_t LOCAL = RTEMS_LOCAL;
	static const Attribute_t GLOBAL = RTEMS_GLOBAL;
	static const Attribute_t FIFO = RTEMS_FIFO;
	static const Attribute_t PRIORITY = RTEMS_PRIORITY;
	static const Attribute_t NO_FLOATING_POINT = RTEMS_NO_FLOATING_POINT;
	static const Attribute_t FLOATING_POINT = RTEMS_FLOATING_POINT;
	//API Modes:
	static const OpusMode_t ALL_MODE_MASKS = RTEMS_ALL_MODE_MASKS;
	static const OpusMode_t DEFAULT_MODES = RTEMS_DEFAULT_MODES;
	static const OpusMode_t CURRENT_MODE = RTEMS_CURRENT_MODE;
	static const OpusMode_t PREEMPT = RTEMS_PREEMPT;
	static const OpusMode_t NO_PREEMPT = RTEMS_NO_PREEMPT;
	static const OpusMode_t NO_TIMESLICE = RTEMS_NO_TIMESLICE;
	static const OpusMode_t TIMESLICE = RTEMS_TIMESLICE;
	static const OpusMode_t ASR = RTEMS_ASR;
	static const OpusMode_t NO_ASR = RTEMS_NO_ASR;
	//API Time and Timing
	static const Interval_t MILISECOND_WAIT = 1;
	static const Interval_t NO_TIMEOUT = RTEMS_NO_TIMEOUT;
	static const TaskId_t TASK_MYSELF = RTEMS_SELF;
	static const size_t MINIMUM_STACK_SIZE = RTEMS_MINIMUM_STACK_SIZE;
	/**
	 * This is a helper method to build a qualified name out of single characters
	 * @param c1	The first character
	 * @param c2	The second character
	 * @param c3	The third character
	 * @param c4	The fourth character
	 * @return	A name suitable for use for the Operating System
	 */
	static Name_t buildName(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4);
	/**
	 * This method returns the number of clock ticks per second.
	 * In RTEMS, this is typically 1000.
	 * @return	The number of ticks.
	 */
	static Interval_t getTicksPerSecond(void);
	/**
	 * This system call sets the system time.
	 * To set the time, it uses a TimeOfDay_t struct.
	 * @param time The struct with the time settings to set.
	 * @return	\c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t setClock(TimeOfDay_t* time);
	/**
	 * This system call sets the system time.
	 * To set the time, it uses a timeval struct.
	 * @param time The struct with the time settings to set.
	 * @return	\c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t setClock(timeval* time);
	/**
	 * This system call returns the current system clock in timeval format.
	 * The timval format has the fields \c tv_sec with seconds and \c tv_usec with
	 * microseconds since an OS-defined epoch.
	 * @param time	A pointer to a timeval struct where the current time is stored.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t getClock_timeval(timeval* time);

	/**
	 * Get the time since boot in a timeval struct
	 *
	 * @param[out] time A pointer to a timeval struct where the uptime is stored.
	 * @return\c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t getUptime(timeval* uptime);

	/**
	 * Get the time since boot in milliseconds
	 *
	 * This value can overflow! Still, it can be used to calculate time intervalls
	 * between two calls up to 49 days by always using uint32_t in the calculation
	 *
	 * @param ms uptime in ms
	 * @return RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t getUptime(uint32_t* uptimeMs);

	/**
	 * Returns the time in microseconds since an OS-defined epoch.
	 * The time is returned in a 64 bit unsigned integer.
	 * @param time A pointer to a 64 bit unisigned integer where the data is stored.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t getClock_usecs(uint64_t* time);
	/**
	 * Returns the time in a TimeOfDay_t struct.
	 * @param time A pointer to a TimeOfDay_t struct.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t getDateAndTime(TimeOfDay_t* time);
	/**
	 * Converts a time of day struct to POSIX seconds.
	 * @param time The time of day as input
	 * @param timeval The corresponding seconds since the epoch.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to);
	/**
	 * Commands the calling task to sleep for a certain number of clock ticks.
	 * Typically other tasks are executed then.
	 * @param ticks	The number of clock ticks to sleep.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t sleepFor(Interval_t ticks);

	/**
	 * With this call, a new task is created.
	 * The task is created (its resources are acquired), but it is not started.
	 * @param name	A name as specified in the OS.
	 * @param initial_priority	The task's priority. Ranging from 0 (lowest) to 99 (highest).
	 * @param stack_size		The stack size reserved for this task.
	 * @param initial_modes		Options for the task's mode (preemptible, time slicing, etc..)
	 * @param attribute_set		Options for the task's attributes (floating point, local/global)
	 * @param id				The OS returns the task id, that uniquely identifies the task.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t createTask(Name_t name,
			TaskPriority_t initial_priority, size_t stack_size,
			OpusMode_t initial_modes, Attribute_t attribute_set, TaskId_t *id);
	/**
	 * Finds a task with the help of its name.
	 * @param name	Name of the task to find
	 * @param id	The OS returns the task id, that uniquely identifies the task.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t findTask(Name_t name, TaskId_t *id);
	/**
	 * Starts a task.
	 * The task immediately starts running.
	 * @param id The task id.
	 * @param entry_point	A pointer to the (static) method that is executed by the task.
	 * @param argument	One argument (a void* pointer) may be passed to the task.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t startTask(TaskId_t *id, TaskEntry_t entry_point,
			TaskArgument_t argument);
	/**
	 * With this call, tasks are deleted from the system
	 * @param id	The task id.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t deleteTask(TaskId_t *id);
	/**
	 * Checks if the current executing context is an ISR.
	 * @return true if handling an interrupt, false else.
	 */
	static bool isInterruptInProgress();
	/**
	 * An task is not executed periodically by default.
	 * This is activated with this call. This is managed internally.
	 * @param period		The task's period in clock ticks.
	 * @param[out] periodId	The newly created period's id
	 * @param name			optional name for the period
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t setAndStartPeriod(Interval_t period, PeriodId_t *periodId, Name_t name = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'));
	/**
	 * This call must be made in a periodic task, when activities of one cycle are finished.
	 * This is managed internally.
	 * @param periodId	Id of the period as returned by setAndStartPeriod()
	 * @param period	The period duration for the next cycle.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t checkAndRestartPeriod(PeriodId_t periodId, Interval_t period);
	/**
	 * This call deletes the period.
	 * This is managed internally.
	 * @param id	Pointer to the task identifier the period belongs to.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t deletePeriod(TaskId_t *id);
	/**
	 * With this call the period statistics (and therefore the periodic task
	 * statistics) are printed to the screen.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t reportPeriodStatistics();

	/**
	 * With this call, a new message queue is created.
	 * @param name		A qualified name for the message queue.
	 * @param count		Number of messages the queue can store before it rejects new messages.
	 * @param max_message_size	Maximum size of a single message.
	 * @param attribute_set		Attributes for the message queue (fifo/priority, local/global)
	 * @param id		A unique message queue identifier returned by the OS.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t createMessageQueue(Name_t name, uint32_t count,
			size_t max_message_size, Attribute_t attribute_set,
			MessageQueueId_t *id);
	/**
	 * Returns a message queue id by its name.
	 * @param name	The queue's name.
	 * @param id	A pointer to the queue id to return to.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t findMessageQueue(Name_t name, MessageQueueId_t *id);
	/**
	 * Sends a message to the queue given by id.
	 * @param id		Id of the queue to send to
	 * @param buffer	A pointer to any kind of data to send over the queue.
	 * @param size		Size of the data to send.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t sendMessage(MessageQueueId_t id, const void *buffer,
			size_t size);
	/**
	 * Checks, if a message was received by a queue with identifier id.
	 * @param id		The id of the checked task.
	 * @param buffer	Pointer to the buffer to store to.
	 * @param bufSize	Maximum size of the buffer.
	 * @param recSize	The actual message size is returned here.
	 * @param option_set	Specifies, if the task waits for a message (WAIT/ NO_WAIT).
	 * @param timeout	If the task waits, this interval specifies how long (in clock ticks).
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t receiveMessage(MessageQueueId_t id, void *buffer,
			size_t bufSize, size_t *recSize, Option_t option_set,
			Interval_t timeout);
	/**
	 * Deletes all pending messages in a certain queue.
	 * @param id	Id of the queue to flush
	 * @param count	Number of flushed messages.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t flushMessageQueue( MessageQueueId_t id, uint32_t* count );
	/**
	 * Deletes a message queue from the system.
	 * @param id	Id of the queue to delete.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t deleteMessageQueue(MessageQueueId_t *id);

	/**
	 * Creates a new mutual exclusive lock (or semaphore).
	 * With these locks, concurrent access to system resources (data pool, ...) can be
	 * controlled.
	 * @param name	A qualified name for the mutex.
	 * @param id	The mutex's id as returned by the OS.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t createMutex(Name_t name, MutexId_t *id);
	/**
	 * Deletes the mutex identified by id.
	 * @param id Id of the mutex to delete.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t deleteMutex(MutexId_t *id);
	/**
	 * With this call, a task tries to acquire the mutex.
	 * Must be used in conjunction with unlockMutex.
	 * @param id		Id of the mutex to acquire.
	 * @param timeout	Specifies how long a task waits for the mutex. Default is NO_TIMEOUT.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t lockMutex(MutexId_t *id, Interval_t timeout);
	/**
	 * Releases a mutex.
	 * Must be used in conjunction with lockMutex.
	 * @param id	Id of the mutex to release.
	 * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t unlockMutex(MutexId_t *id);
	/**
	 * Establishes a new interrupt service routine.
	 * @param handler	The service routine to establish
	 * @param interrupt	The interrupt (NOT trap type) the routine shall react to.
	 * @return	RETURN_OK on success. Otherwise, the OS failure code is returned.
	 */
	static ReturnValue_t setInterruptServiceRoutine(IsrHandler_t handler, InterruptNumber_t interrupt, IsrHandler_t *oldHandler = NULL );
	/**
	 * Enables the interrupt given.
	 * The function tests, if the InterruptMask register was written successfully.
	 * @param interrupt The interrupt to enable.
	 * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else.
	 */
	static ReturnValue_t enableInterrupt( InterruptNumber_t interrupt );
	/**
	 * Disables the interrupt given.
	 * @param interrupt The interrupt to disable.
	 * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else.
	 */
	static ReturnValue_t disableInterrupt( InterruptNumber_t interrupt );
};

#endif /* API */
#endif /* OSAL_H_ */