/*-----------------------------------------------------------------------------
cms.h -- CAN Message Specification CMS

Copyright (c) 1994 JANZ Computer AG
All Rights Reserved

Created 94/10/11 by Soenke Hansen
Version 1.32 of 99/06/18

Definitions and type definitions for COB's and CMS Objects.
Prototypes of functions defined in cms.c.

-----------------------------------------------------------------------------*/


#ifndef cms_DEFINED
#define cms_DEFINED

#ifdef __cplusplus
extern "C" {
#endif

#include "defs.h"

#define COB_LEN		 8	/* max. data length of CAN message */
#define CMS_NAME_LEN	13	/* cf. CiA/DS207 */
#define COB_NAME_LEN	14	/* CMS_NAME_LEN + 1 */


/* COB types */
#define COB_RECEIVE		 0
#define COB_TRANSMIT	 1


/* Kinds of CMS objects */
#define CMS_VARIABLE		0x0000
#define CMS_VARSET		0x1000
#define CMS_DOMAIN		0x2000
#define CMS_EVENT		0x3000
#define cmso_kind(type) ((type) & 0xf000)

/* Classes of CMS objects */
#define CMS_BASIC		0x0100
#define CMS_MULTIPLEXED		0x0200
#define CMS_CONTROLLED		0x0100
#define CMS_UNCONTROLLED	0x0200
#define CMS_STORED		0x0300
#define cmso_class(type) ((type) & 0x0300)

/* User types of CMS objects */
#define CMS_CLIENT		0x0010
#define CMS_SERVER		0x0020
#define cmso_user(type) ((type) & 0x0030)

/* Access types of Variables */
#define CMS_READ_ONLY		0x0001
#define CMS_WRITE_ONLY		0x0002
#define CMS_READ_WRITE		0x0003
#define cmso_access(type) ((type) & 0x0007)


#ifdef FIRMWARE

/* CAN Communication Object */
struct cob {
	BYTE_t		tc;		/* COB type and class */
	BYTE_t		prio;		/* priority */
	WORD_t		inht;		/* inhibit time */
	WORD_t		head;		/* COB head (descriptor) */
	BYTE_t		*nmcms;		/* name of CMS object */
	BYTE_t		nmsfx;		/* suffix of COB name */
	struct calo	*co;		/* parent CAL object */
	struct cob	*next;		/* list of used COBs */
};

#define NIL_COB (struct cob *)0

/* Set and get COB attributes */
#define cob_length(cob) ((cob)->head & 0x000f)
#define cob_tc(t,c) (((c) & 0x07) | (((t) & 0x01) << 4))
#define cob_class(cob) ((cob)->tc & 0x07)
#define cob_type(cob) (((cob)->tc >> 4) & 0x01)


/* Data set size type (for domains) */
#if TYPEDEFS == 1
typedef unsigned long	DSIZE_t;	/* 32 bit unsigned integer */
#else
#define DSIZE_t unsigned long
#endif

/* Components of messages in domain call-backs */
#define dom_spec	u.m2.r		/* sub-specifier MS_DOM_* */
#define dom_reason	u.m2.b[0]	/* reason for failure */

#define	cms_spec	u.m2.r		/* cms sub-specifier MS_CMS_DATA */
#define	cms_id		u.m2.d		/* cms object id */
#define cms_failure	u.m2.b[0]	/* cms failure code */

/* Location of data set size in message. */
#define dsize_in_msg(m) (&(m)->u.m2.b[4])

/* Convert between data set size and an array of 4 bytes */
#define dsize_from_bytes(b) ((DSIZE_t)(b)[0] + ((DSIZE_t)(b)[1] << 8) + \
		((DSIZE_t)(b)[2] << 16) + ((DSIZE_t)(b)[3] << 24))

/* Domain specific state */
struct domain {
	BYTE_t		*data;	/* data buffer provided by application */
	DSIZE_t		len;	/* allocated length of buffer */
	DSIZE_t		rlen;	/* actual length of data received */
	DSIZE_t		dsize;	/* data set size if positive */
	BYTE_t		ics;	/* initial command specifier */
	BYTE_t		cs;	/* segment command spec. except for "n" */
	BYTE_t		csb;	/* backup of command specifier */
	BYTE_t		more;	/* more data blocks to be transferred? */
	BYTE_t		pos;	/* position in CAN message buffer */
	BYTE_t		mux[3];	/* buffer for multiplexer */
	int		muxlen;	/* length of multiplexer */
	struct message	*dm;	/* delayed message */
	WORD_t		config; /* some configurations */
	int		pend_ack; /* flags for pending acknowlegdes */
	int		del_ack;  /* does delayed message need ack? */
	int		delayed;  /* set if delay occurs */
};

#endif /* FIRMWARE */


/* Flags in config/pend_ack */
#define	CMS_INHIBIT_CONFIG		1	/* multiplexor */
/* flags will be interpreted as default inhibit time (for CANopen PDOs) */

#define	CMS_DOMAIN_GENERAL_CONFIG	0	/* multiplexor */
#define DOM_ACKNOWLEDGE			(1<<0)
#define DOM_SDO_EVERY_STATE_ACTIV	(1<<8)
#define DOM_RCPT_ACKNOWLEDGE		(1<<1)

/* Flags for configuring CMS domains at their creation */
#define DOM_SDO_DBT_CAPABILITY		(1<<0)	
	/* Flag specifies, if it is allowed to distribute the SDO-CMS 
	 * object`s identifier by DBT services in preparing phases
	 * (CAL boot up for CANopen slaves).  
	 */

#ifdef FIRMWARE

/* Domains must be in the idle state to accept service requests. */
#define dom_set_idle(dom) ((dom)->ics = 0xff)
#define dom_is_idle(dom) ((dom)->ics == 0xff)

#define dom_is_delayed(dom) ((dom)->delayed != 0)

/* True if the COB is a data COB with type COB_RECEIVE or is a remote COB
   with type COB_TRANSMIT */
#define cob_accept(cob) ((((cob)->head ^ (WORD_t)((cob)->tc)) & 0x0010) == 0)



/* This linked list holds the created (and enabled, coded!) TPDOs */
struct pdoSendList {
	struct cmso			*cmsIdOfPdo;	/* cms object id of TPDO */
	struct pdoSendList	*next;			/* pointer to next object */
};
#define	NIL_PDO_SEND_LIST (struct pdoSendList *)0

struct pdoMapList {
#ifdef CAL_CANOPEN_CLAMPED
	LWORD_t				cmsObjectMappingEntry;
#else
	unsigned char		*offsetInDpm;
#endif
	BYTE_t				mapLength;
	struct pdoMapList	*next;
};
#define	NIL_PDO_MAP_LIST	(struct pdoMapList *)0

/* CANopen add on to CMS Object; is only used at PDOs */
struct copAddOn {
	BYTE_t				transType;
	BYTE_t				actualTransCount;
	BYTE_t				state;
	struct pdoMapList	*mapList;
};
#define	NIL_COP_ADD_ON (struct copAddOn *)0
/* values of state of PDO */
#define	BIT_PDO_ENABLED		(1 << 0)
#define	BIT_PDO_DISABLED	(0 << 0)



/* CMS Object */
struct cmso {
	BYTE_t		*name;		/* name of CMS Object */
	WORD_t		type;		/* var/dom/evt,bas/mux,user,access */
	BYTE_t		*buf;		/* buffer pointer */
	BYTE_t		dbuf[COB_LEN];	/* data buffer */
	BYTE_t		mux;		/* save multiplexor here */
	struct domain	*dom;		/* domain specific */
	WORD_t		flags;		/* special flags for internal use */
	WORD_t		tid;		/* id for usage with timer timeout ? */
	WORD_t		hid;		/* host assigned object id */
	OBJECT		adata;		/* application data */
	void		(*ahdl)();	/* application handler CMS messages */
	struct cob	*cobs;		/* list of used COBs */
	struct cob	rxcob;		/* receive COB */
	struct cob	txcob;		/* transmit COB */
	struct cmso	*next;		/* list of CMS Objects */
	OBJECT		obj;		/* associated CAL Object */
#ifdef nodef
    perhaps TODO: inhibit the possibility to send user-data in cms-objects
    which will be driven by e.g. TPU irqs and get their data from module!
	BYTE_t		canopen_flags	/* signals special canopen behavior */
					/* of cms-object (e.g. TIME, SYNC) */
#endif
	struct copAddOn	*canOpenControls;
};

#define NIL_CMSO (struct cmso *)0

#endif /* FIRMWARE */

/* Various flags */
#define INHIBITED	0x01
#define TX_REQUEST	0x02
#define TX_REQUEST_CON	0x04
#define ENABLED		0x08

#define OUTSTANDING     0x10
#define RW_REQUEST_MASK 0x20
#define WRITE_REQUEST   0x20


/* Timer/BCAN request Id modifiers */
#define REQ_INHIBIT_TIME	(0x1000 & ~CALID_MASK)
#define REQ_CON_TIMEOUT 	(0x2000 & ~CALID_MASK)

#ifdef FIRMWARE

/* Disable CMS Definition services */
extern int DisableDefCms(void);

/* Enable CMS Definition services */
extern void EnableDefCms(void);

/* Check if CMS Definition services are disabled */
extern int IsDisabledDefCms(void);

/* Initialize the CMS Object Directory */
extern void InitCms(WORD_t);

/* Create a CMS Object */
struct cmso *NewCmsO(BYTE_t *);

/* Create a special CMS Object without adding it to directory */
struct cmso *NewCmsONoDBT(BYTE_t *);

/* Set host assigned id for a CMS Object */
void SetCmsOhid(struct cmso *co, WORD_t id);

/* Delete a CMS Object */
extern void DeleteCmsO(struct cmso *);

/* Get a CMS Object by name */
extern struct cmso *GetCmsO(BYTE_t *);

/* Get next CMS Object.  Used when looping through the defined CMS Objects. */
extern struct cmso *GetNextCmsO(int);

/* Get next COB used by a CMS Object. */
extern struct cob *GetNextCobCms(int);

/* Construct COB name */
extern void cob_name(struct cob *, BYTE_t *);

/* Invocation of (remote) CMS service for a CMS object. */
extern int cms_invoke(struct cmso *, BYTE_t *, int);

/* Handler for non-CAN messages to CMS objects. */
extern void cms_no_can_hdl(struct cmso *, struct message *);


/*------ Application handler function --------------------------------------*/

/* Default application handler for CMS objects. */
extern void DfltApplHdlCms(struct cmso *, struct message *);
#define NIL_AHDL DfltApplHdlCms

#endif /* FIRMWARE */

/* Specific flags for JANZ */
#define CMS_USE_HOST_ID		(1<<0)


/*------ CMS Variables -----------------------------------------------------*/

#ifdef FIRMWARE

/* Definition of a CMS Multiplexed Variable */
struct cmso *MultiplexedVariable(
        BYTE_t  *,	/* name of CMS object to be created */
        WORD_t  ,	/* user and access type */
        int     ,	/* length of data type (<=8) */
        int     ,	/* range: [0,7] */
        OBJECT  ,	/* application data */
        void    (*)()	/* appl. handler for CMS messages */
);


/* Definition of a CMS Basic Variable */
extern struct cmso *BasicVariable(
	BYTE_t	*,	/* name of CMS object to be created */
	WORD_t	,	/* user and access type */
	int	,	/* length of data type (<=8) */
	int	,	/* range: [0,7] */
	OBJECT	,	/* application data */
	void	(*)()	/* appl. handler for CAN data frames */
);

/* Definition of a CMS Basic Variable for SYNC features */
extern struct cmso *BasicVariableSYNC(
	BYTE_t  *,      /* name of CMS object to be created */
	WORD_t  ,       /* user and access type */
	int     ,       /* length of data type (<=8) */
	int     ,       /* range: [0,7] */
	OBJECT  ,       /* application data */
	void    (*)(),  /* appl. handler for CAN data frames */
	WORD_t,         /* predefined transmit ID */
	WORD_t,         /* predefined receive ID */
	BYTE_t          /* DBT capibilities */
);

/* Update Read-Only Variable in Server */
extern int UpdateVariable(struct cmso *, BYTE_t *);

/* Client requests Write Variable Service */
extern int WriteVariableReq(struct cmso *, BYTE_t *);

/* Client requests Read Variable Service */
extern int ReadVariableReq(struct cmso *);

/* Client requests Write Variable Service for multiplexed variables. */
int WriteMultiplexedVariableReq(struct cmso *co, int mux, BYTE_t *value);

/* Client requests Read Variable Service. */
int ReadMultiplexedVariableReq(struct cmso *co, int mux);


/* Server responds to a Write Variable Service */
int WriteVariableRes(struct cmso *, int , BYTE_t *);

/* Server responds to a Write Variable Service */
int ReadVariableRes(struct cmso *co, int status, BYTE_t *value);



/*------ CMS Events --------------------------------------------------------*/

/* Definition of a CMS Uncontrolled Event */
extern struct cmso *UncontrolledEvent(
	BYTE_t	*,	/* name of CMS object to be created */
	WORD_t	,	/* user type */
	int	,	/* length of data type (<=7) */
	int	,	/* range: [0,7] */
	OBJECT	,	/* application data */
	void	(*)()	/* appl. handler for CMS messages */
);

/* Definition of a CMS Controlled Event */
extern struct cmso *ControlledEvent(
	BYTE_t	*,	/* name of CMS object to be created */
	WORD_t	,	/* user type */
	int	,	/* length of data type (<=7) */
	int	,	/* range: [0,7] */
	OBJECT	,	/* application data */
	void	(*)()	/* appl. handler for CMS messages */
);

/* Definition of a CMS Stored Event */
extern struct cmso *StoredEvent(
	BYTE_t	*,	/* name of CMS object to be created */
	WORD_t	,	/* user and access type */
	int	,	/* length of data type (<=8) */
	int	,	/* range: [0,7] */
	OBJECT	,	/* application data */
	void	(*)()	/* appl. handler for CMS messages */
);

/* Definition of a Stored Event for CANopen TIMESTAMP object */
extern struct cmso *StoredEventTS(
	BYTE_t  *,      /* name of CMS object to be created */
	WORD_t  ,       /* user and access type */
	int     ,       /* length of data type (<=8) */
	int     ,       /* range: [0,7] */
	OBJECT  ,       /* application data */
	void    (*)(),  /* appl. handler for CAN data frames */
	WORD_t,         /* predefined transmit ID */
	WORD_t,         /* predefined receive ID */
	BYTE_t          /* DBT capibilities */  
);

/* Definition of a Stored Event for CANopen EMERGENCY object */
extern struct cmso *StoredEventEMCY(
	BYTE_t  *,      /* name of CMS object to be created */
	WORD_t  ,       /* user and access type */
	int     ,       /* length of data type (<=8) */
	int     ,       /* range: [0,7] */
	OBJECT  ,       /* application data */
	void    (*)(),  /* appl. handler for CAN data frames */
	WORD_t,         /* predefined transmit ID */
	WORD_t,         /* predefined receive ID */
	BYTE_t          /* DBT capibilities */  
);

/* Definition of a Stored Event for CANopen PDO */
extern struct cmso *StoredEventPDO(
	BYTE_t  *,      /* name of CMS object to be created */
	WORD_t  ,       /* user and access type */
	int     ,       /* length of data type (<=8) */
	int     ,       /* range: [0,7] */
	OBJECT  ,       /* application data */
	void    (*)(),  /* appl. handler for CAN data frames */
	WORD_t,         /* predefined transmit ID */
	WORD_t,         /* predefined receive ID */
	BYTE_t          /* DBT capibilities */  
);

/* Notify Event service. */
extern int NotifyEvent(struct cmso *, BYTE_t *);

/* Store Event service. */
extern int StoreEvent(struct cmso *, BYTE_t *, int);

/* Read Event service. */
extern int ReadEvent(struct cmso *);

/* Set Event Control State service. */
extern int SetControlEventReq(struct cmso *, int);
extern int SetControlEventRes(struct cmso *, int, int, BYTE_t *);

/*-------- CMS Domains ------------------------------------------------------*/

/* Implemented in cmsdom.c */

/* Definition of a CMS Domain */
extern struct cmso *Domain(
	BYTE_t	*,		/* name of CMS object to be created */
	WORD_t	,		/* class and user type */
	int	,		/* multiplexer length (<=3) */
	int	,		/* range: [0,7] */
	OBJECT	,		/* application data */
	void	(*)()		/* appl. handler for CMS messages */
);

/* Definition of a CMS Domain for CANopen SDOs */
extern struct cmso *DomainSDO(
	BYTE_t	*,		/* name of CMS object to be created */
	WORD_t	,		/* class and user type */
	int	,		/* multiplexer length (<=3) */
	int	,		/* range: [0,7] */
	OBJECT	,		/* application data */
	void	(*)(),		/* appl. handler for CMS messages */
	WORD_t  Tx_SDO_ID,      /* Transmit SDO ID as seen by node */
        WORD_t  Rx_SDO_ID,      /* Receive SDO ID as seen by node */
	BYTE_t  dbt_cap		/* DBT capability flag of CANopen node */
);

/* Abort Domain Transfer */
extern void DomAbortReq(
	struct cmso	*,	/* Domain CMS object */
	BYTE_t		*	/* nil or 4 bytes */
);

/* Client requests the statrt of normal domain download.
   Subsequently transfer of the data block, if provided by the client,
   will start.  Expedited transfer will be chosen iff 0<dsize<=4, len==dsize,
   and exped!=0 (expedited enabled) else normal transfer is started.
   The client is called back on service completion or else for more data. */
extern int DomDownloadStartReq(
	struct cmso	*,	/* the domain handle */
	BYTE_t		*,	/* multiplexor */
	BYTE_t		*,	/* (first) data block to be downloaded */
	DSIZE_t		,	/* length of (first) data block */
	DSIZE_t		,	/* data set size if > 0 */
	int		,	/* enable expedited transfer */
	int			/* true if more blocks will follow */
);

/* Client request the continuation of a download and provides the next
   data block to be transfered after having received to confirmation
   for the previous block if any.  If the client provides no data (len==0)
   then the service completes successfully.  If more is true then the
   client wishes to be asked for additional data blocks. */
extern int DomDownloadContReq(
	struct cmso	*,	/* the domain handle */
	BYTE_t		*,	/* (next) data block to transmit/receive */
	DSIZE_t		,	/* allocated length of data block */
	int			/* true if more blocks will follow */
);

/* Server responds to download request providing a receive buffer for
   data to be downloaded.  The buffer must be able to hold 7 bytes
   at least. */
extern int DomDownloadRes(
	struct cmso	*,	/* the domain handle */
	BYTE_t		*,	/* (next) data block to transmit/receive */
	DSIZE_t			/* allocated length of data block */
);

/* Client requests initialization of a domain upload.
   The client will be called back to to receive expedited data or to
   provide buffers to receive data blocks of a normal transfer.
   Note that the server decides about using normal or expedited transfer. */
extern int DomUploadStartReq(
	struct cmso	*,	/* the domain handle */
	BYTE_t		*	/* multiplexor */
);

/* The server received a domain upload indication.  The server
   responds by calling the following function to accept the upload
   request.  Expedited transfer will be chosen iff 0<dsize<=4, len==dsize,
   and exped!=0 (expedited enabled) else normal transfer is started.
   In case of multiplexed domains the data must be consistent with
   the multiplexor received on indication.
   The server will be called back for more data to be uploaded if necessary.
   The server will be called back on completion of the service. */
extern int DomUploadRes(
	struct cmso	*,	/* the domain handle */
	BYTE_t		*,	/* (first) data block to be uploaded */
	DSIZE_t		,	/* length of (first) data block */
	DSIZE_t		,	/* data set size if > 0 */
	int		,	/* enable expedited transfer */
	int			/* true if more blocks will follow */
);

/* Client requested the continuation of a upload.  Server provides the next
   data block to be transfered.  If the server provides no data (len==0)
   then the service completes successfully.  If more is true then the
   server wishes to be asked for additional data blocks. */
extern int DomUploadContRes(
	struct cmso	*,	/* the domain handle */
	BYTE_t		*,	/* (next) data block to transmit/receive */
	DSIZE_t		,	/* allocated length of data block */
	int			/* true if more blocks will follow */
);

extern void DomHostAcknowledgeRes(
	struct cmso	*co
);

extern void DomRcptAcknowledgeReq(
	struct cmso	*co
);

#endif /* FIRMWARE */

/* bitpositions in cs */
#define	D_MORE		(1 << 0)	/* more date will follow */
#define	D_EXPED		(1 << 1)	/* inhibit expedited data transfer */
#define	D_SUCCESS	(1 << 2)	/* success indication */

#ifdef __cplusplus
}
#endif

#endif /* !cms_DEFINED */
