/**
 * \file RDMOD16X.C
 * 
 * \author Axel Wolf, SCI Cupertino
 * \author Dr. Jens Barrenscheen, HL MC PD, Munich
 * \author Hubert Piontek, University of Ulm
 *
 * Routine for reading data from the last message object
 *
 * Most of this is based von the Infineon/Siemens Application Note AP2922.
 * Some additions made at University of Ulm, February 2003.
 *
 * This CAN driver is mainly meant to be used by the publisher/subscriber
 * library developed at the University of Ulm, 1999-2003.
 */

/*********************************************************************
 * Program name:	"RDMOD16X.C"                                     *
 * Compiler used:	BSO/Tasking C166                                 *
 * Task:		Source File for procedure rd_modata_16x              *
 *			belonging to Siemens ApNote AP2922                       *
 *			"'C' CAN Driver Routines for the C166 family"            *
 *                                                                   * 
 * Last modifications:	April 28nd 1997                              *
 * Version:		1.0                                                  *
 * Authors:		Axel Wolf,  SCI Cupertino                            *
 *			Dr. Jens Barrenscheen, HL MC PD, Munich                  *
 *********************************************************************/

extern unsigned int  *id_ptr_16x[16];		///< pointer to message id's (UAReg)
extern unsigned char *db0_ptr_16x[16];		///< pointer to 'databyte 0's
extern unsigned int  *msgctrl_ptr_16x[16];	///< pointer to message control registers
extern unsigned char *msgconf_ptr_16x[16];	///< pointer to message configuration registers
extern unsigned char dir_bit_16x[16];		///< DIR bits MO 1...15
extern unsigned char xtd_bit_16x[16];		///< XTD bits MO 1...15
extern unsigned char dlc_16x[16];			///< data byte lengths MO 1...15

/**
 * Use this function to read received data (and the message id) from the specified message object (#1..#14).
 *
 * \param nr Number of the message object to read from (1..14)
 * \param *downl_data_ptr Pointer to a buffer where the received data will be put.
 * \param *mo_id_ptr Pointer to a long where the message id of the newly received message will be put.
 * \param *mo_dlc_ptr Pointer to a character where the length of the received message will be put.
 *
 * \warning *downl_data_ptr must point to an array large enough to hold all received data. Always make this
 *          large enough for the largest possible amount of payload, being 8 bytes.
 *
 * \note The reading of the data bytes is repeated if a new message comes in
 * for message 'nr' during the data bytes are read, because the CAN module
 * sets NEWDAT in this case. 
 */
void rd_modata_16x(unsigned char nr, unsigned char *downl_data_ptr, unsigned long *mo_id_ptr, unsigned char *mo_dlc_ptr)
{

	unsigned char i, dummy_char;
	unsigned char *dummy_dbptr;
	unsigned int *dummy_idptr;
	unsigned int dummy_int1, dummy_int2;

	if ((nr<15) && (nr)) {
		do {
			dummy_char=*msgconf_ptr_16x[nr];
			// added hp 2003-02-24:
			*mo_dlc_ptr = (dummy_char>>4);

			dummy_idptr=id_ptr_16x[nr];
			if (xtd_bit_16x[nr]) {		/* calculate XTD ID: */
		   		dummy_int1=*dummy_idptr++;
		   		dummy_int2=*dummy_idptr;
		   		dummy_int1=(dummy_int1<<8)+(dummy_int1>>8);
		   		dummy_int2=(dummy_int2<<8)+(dummy_int2>>8);
		   		*mo_id_ptr=((((unsigned long)(dummy_int1))<<16) + dummy_int2)>>3;
			} else {				/* calculate STD ID: */
		   		dummy_int1=*dummy_idptr;
		   		*mo_id_ptr=(unsigned long) (((dummy_int1<<8)+(dummy_int1>>8))>>5);
			}
			// end of addition

			/* store actual data length code */
			dlc_16x[nr]=(dummy_char>>4);
			/* clr NEWDAT and INTPND */
			*msgctrl_ptr_16x[nr]=0xfdfd;
			/* load dummy ptr (db 0) */
			dummy_dbptr=db0_ptr_16x[nr];
			/* move data bytes from MO's data bytes to download buffer */
			for (i=0;i<dlc_16x[nr];i++) 
				*downl_data_ptr++ = *dummy_dbptr++;
	   	} while (*msgctrl_ptr_16x[nr] & 0x0200);	/* while NEWDAT=1 */
	}
}