#ifndef _RTAI_PQUEUE_WRAPPER_H
#define _RTAI_PQUEUE_WRAPPER_H
//////////////////////////////////////////////////////////////////////////////
//
//      Copyright (©) 1999 Zentropic Computing, All rights reserved
//
// Authors:             Trevor Woolven (trevw@zentropix.com)
// Original date:       Thu 15 Jul 1999
// Id:                  @(#)$Id: rtai_pqueue_wrapper.h,v 1.3 2005/03/18 09:29:59 rpm Exp $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
//
// pqueues interface for Real Time Linux.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C" {
#endif

#include "linux_wrapper.h"
#include "rtai.h"
#include "rtai_pthread_wrapper.h"
#include "zdefs.h"

// ----------------------------------------------------------------------------
#define TASK_FPU_DISABLE 0
#define TASK_FPU_ENABLE 1

//Posix definitions
#define	MQ_OPEN_MAX	8	//Maximum number of message queues per process
#define	MQ_PRIO_MAX	32	//Maximum number of message priorities
#define	MQ_BLOCK	0	//Flag to set queue into blocking mode
#define	MQ_NONBLOCK	1	//Flag to set queue into non-blocking mode
#define MQ_NAME_MAX	80	//Maximum length of a queue name string

#define MQ_MIN_MSG_PRIORITY 0		//Lowest priority message
#define MQ_MAX_MSG_PRIORITY MQ_PRIO_MAX //Highest priority message

//Definitions to support higher-level applications
typedef enum {FIFO_BASED, PRIORITY_BASED} QUEUEING_POLICY;
typedef enum {POSIX, VxWORKS} QUEUE_TYPE;

// ----------------------------------------------------------------------------
//Posix Queue Attributes
struct mq_attr {
    long mq_maxmsg;		//Maximum number of messages in queue
    long mq_msgsize;		//Maximum size of a message (in bytes)
    long mq_flags;		//Blocking/Non-blocking behaviour specifier
				// not used in mq_open only relevant for 
				// mq_getattrs and mq_setattrs
    long mq_curmsgs;		//Number of messages currently in queue
};
typedef struct mq_attr MQ_ATTR;

typedef union sigval {
	int sival_int;
	void *sival_ptr;
} sigval_t;

/*
 * sigevent definitions
 * 
 * It seems likely that SIGEV_THREAD will have to be handled from 
 * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
 * thread manager then catches and does the appropriate nonsense.
 * However, everything is written out here so as to not get lost.
 */
#define SIGEV_SIGNAL	0	/* notify via signal */
#define SIGEV_NONE	1	/* other notification: meaningless */
#define SIGEV_THREAD	2	/* deliver via thread creation */

#define SIGEV_MAX_SIZE	64
#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)

typedef struct sigevent {
	sigval_t sigev_value;
	int sigev_signo;
	int sigev_notify;
	union {
		int _pad[SIGEV_PAD_SIZE];

		struct {
			void (*_function)(sigval_t);
			void *_attribute;	/* really pthread_attr_t */
		} _sigev_thread;
	} _sigev_un;
} sigevent_t;

//Notification data
struct notify {
    RT_TASK *task;
    struct sigevent data;
};

// ----------------------------------------------------------------------------
//Generic Message format
//TODO: Consider moving this definition into rtai_utils.h
struct msg_hdr {
    BOOL in_use;
    size_t size;		//Actual message size
    uint priority;		//Usage priority (message/task)
    void *next;			//Pointer to next message on queue
};
typedef struct msg_hdr MSG_HDR;

//Generic queue header 
struct queue_control {
    void *base;		//Pointer to the base of the queue in memory
    void *head;		//Pointer to the element at the front of the queue
    void *tail;		//Pointer to the element at the back of the queue
    MQ_ATTR attrs;	//Queue attributes
};
typedef struct queue_control Q_CTRL;

//Data messages 
struct msg {
    MSG_HDR hdr;
    char data;			//Anchor point for message data
};
typedef struct msg MSG;

// ----------------------------------------------------------------------------
//Posix Queue Descriptors
struct _pqueue_descr_struct {
    RT_TASK *owner;		//Task that created the queue
    int open_count;		//Count of the number of tasks that have
				// 'opened' the queue for access
    char q_name[MQ_NAME_MAX];	//Name supplied for queue
    uint q_id;			//Queue Id (index into static list of queues)
    BOOL marked_for_deletion;	//Queue can be deleted once all tasks have 
				// closed it	
    Q_CTRL data;		//Data queue (real messages)
    mode_t permissions;		//Permissions granted by creator (ugo, rwx)
    struct notify notify;	//Notification data (empty -> !empty)
    pthread_cond_t  emp_cond;   //For blocking on empty queue
    pthread_cond_t  full_cond;  //For blocking on full queue
    pthread_mutex_t mutex;      //For synchronisation of queue
};
typedef struct _pqueue_descr_struct MSG_QUEUE;

// ----------------------------------------------------------------------------
//Task-related Posix Queue data
//A task can open up to MQ_OPEN_MAX pqueues, each with 'potentially'
//different permissions (read, write, blocking/non-blocking etc)
//
struct _pqueue_access_data {
    int q_id;
    int oflags;			//Queue access permissions & blocking spec
};

struct _pqueue_access_struct {
    RT_TASK *this_task;
    int n_open_pqueues;
    struct _pqueue_access_data q_access[MQ_OPEN_MAX];
};
typedef struct _pqueue_access_struct *QUEUE_CTRL;

// ----------------------------------------------------------------------------
typedef unsigned long mqd_t;
#define	INVALID_PQUEUE	0

typedef enum {FOR_READ, FOR_WRITE} Q_ACCESS;

///////////////////////////////////////////////////////////////////////////////
//      ACCESS FUNCTIONS
///////////////////////////////////////////////////////////////////////////////
QUEUEING_POLICY get_task_queueing_policy(void);
QUEUEING_POLICY set_task_queuing_policy(QUEUEING_POLICY policy);

QUEUE_TYPE get_queue_type(void);
QUEUE_TYPE set_queue_type(QUEUE_TYPE type);

///////////////////////////////////////////////////////////////////////////////
//      POSIX MESSAGE QUEUES API
//
// Note that error returns represent the appropriate macro found in errno.h
// eg: -EINVAL, -EBADF etc
//
///////////////////////////////////////////////////////////////////////////////

//--------------------------------< mq_open >----------------------------------
// Create and/or open a message queue
// 
// Return codes:	>= 0 	valid Posix Queue Id
//			< 0	error
//
extern mqd_t mq_open(char *mq_name, int oflags, mode_t permissions, 
						struct mq_attr *mq_attr);

//------------------------------< mq_receive >---------------------------------
// Receive a message from a message queue
//
// Return codes:	>= 0	number of bytes received
//			< 0	error
//
extern size_t mq_receive(mqd_t mq, char *msg_buffer, 
				size_t buflen, unsigned int *msgprio);

//--------------------------------< mq_send >----------------------------------
// Send a message to a queue
//
// Return codes:	>= 0	number of bytes sent
//			< 0	error
extern int mq_send(mqd_t mq, const char *msg, size_t msglen, 
						unsigned int msgprio);

//--------------------------------< mq_close >---------------------------------
// Close a message queue (note that the queue remains in existance!)
//
// Return codes:	= 0	pQueue closed OK
//			< 0	error
//
extern int mq_close(mqd_t mq);

//-------------------------------< mq_getattr >--------------------------------
// Get the attributes of a message queue
//
// Return codes:	= 0	attributes copied successfully
//			< 0	error
//
extern int mq_getattr(mqd_t mq, struct mq_attr *attrbuf);

//-------------------------------< mq_setattr >--------------------------------
// Set a subset of a message queue's attributes
//
// Return codes:	= 0	attributes set successfully
//			< 0	error
//
extern int mq_setattr(mqd_t mq, const struct mq_attr *new_attrs,
				struct mq_attr *old_attrs);

//-------------------------------< mq_notify >---------------------------------
// Register a request to be notified whenever a message arrives on an empty
// queue
// Note that setting the 'notification' parameter to NULL cancels the task's
// earlier notification request
//
// Return codes:	= 0 	notification set/cleared successfully
//			< 0	error
//
extern int mq_notify(mqd_t mq, const struct sigevent *notification);

//-------------------------------< mq_unlink >---------------------------------
// Destroy a message queue
//
// Returns:		= 0 	queue was successfully unlinked
//			< 0	error 
//			> 0 	'n' tasks still have the queue 'open'
//
extern int mq_unlink(char *mq_name);

// ---------------------------------< eof >------------------------------------

#ifdef __cplusplus
}
#endif


#endif  // _RTAI_PQUEUE_WRAPPER_H_
