#include "canr_16x.h"
#include "../ser/ser.h"

/**
 * \file mask.c
 * 
 * \author Axel Wolf, SCI Cupertino
 * \author Dr. Jens Barrenscheen, HL MC PD, Munich
 * \author Hubert Piontek, University of Ulm
 *
 * Added functions to set the global reception mask and low-level interface for the publisher/subscriber library.
 */

/**
 * Each incoming message is filtered through the global mask. Each bit that is set to 1 in the
 * global mask must match the corresponding id bits of the receiving message objects. Each bit that is
 * set to 0 means "don't care" when comparing the id of the incoming message with the receive objects.
 *
 * \param mask Only the lower 29 bits are used. As the layout of the CAN registers within
 * the C166 is kind of strange, we need to do lots of shifting. The exact layout is of no
 * interest to the user of this driver, because it takes care of that. If anyone is interested
 * in the details behind this, (s)he may consult the C166 user's manuals.
 */
void set_global_mask( unsigned long mask )
{
	UGML = ((mask >> 21) & 0xff) | (((mask >> 13) & 0xff) << 8);
	LGML = ((mask >>  5) & 0xff) | ((mask         & 0x1f) << 11);
}

/** 
 * This function handles everything from (re-)defining the first message object
 * to loading the data and transmitting it over the CAN bus. It is used by the publisher/subscriber library.
 * Can also be very useful if you "just want to send a message" ;)
 *
 * \param *cm pointer to a canmsg struct holding the message to be sent.
 *
 * \warning Always uses the first message object. Do not use that one otherwise or do not use this function.
 */
void can_write(canmsg *cm)
{
	// double check the size
  	if(cm->len > 8) 
		cm->len = 8;
	// (re)define the (first) message object.
	def_mo_16x( 1, USE_XTID, cm->id, DIR_XMIT, cm->len, NO_TX_INT, NO_RX_INT );
	// load the payload into the message object
	ld_modata_16x( 1, cm->d );
	// transmit the message
	send_mo_16x( 1 );
}

/**
 * This function checks the specified message object for new data. 
 *
 * \param nr number of the message object to read from
 * \param *cm pointer to a canmsg struct that will hold the received data.
 *
 * \return new data indication
 * \retval 0 There is no new data, *cm is not touched. 
 * \retval >0 There is new data. The message had at least 1 byte of payload. 
 *            The data (and status info like the message id) is copied to *cm, 
 *            and the length of the message is returned. 
 * \retval -1 There is new data. The message had no payload. 
 *            The data (and status info) is copied to *cm, but 
 */
int can_read(int nr, canmsg *cm)
{
	unsigned char len;
	unsigned long id;

	// check for the last object
	if( nr < 15 ) {
		// new data?
		if( !check_mo_16x( nr ) )
			return 0;
		// yes, get it.
		rd_modata_16x( nr, cm->d, &id, &len );
		cm->id = id;
	} else {
		// new data?
		if( !check_mo15_16x() )
			return 0;
		// yes, get it.
		rd_mo15_16x( cm->d, &id, &len );
		cm->id = id;
	}
	// generate a cool return value ;)
	cm->len = (len)?((int)len):-1;
	return cm->len;
}