www.pudn.com > DeviceNet.zip > conn1.c, change:2003-09-19,size:27245b


/***************************************************************************** 
 * 
 * Microchip DeviceNet Stack (Explicit Messaging Connection Object Source) 
 * 
 ***************************************************************************** 
 * FileName:        conn1.c 
 * Dependencies:     
 * Processor:       PIC18F with CAN 
 * Compiler:       	C18 02.20.00 or higher 
 * Linker:          MPLINK 03.40.00 or higher 
 * Company:         Microchip Technology Incorporated 
 * 
 * Software License Agreement 
 * 
 * The software supplied herewith by Microchip Technology Incorporated 
 * (the "Company") is intended and supplied to you, the Company's 
 * customer, for use solely and exclusively with products manufactured 
 * by the Company.  
 * 
 * The software is owned by the Company and/or its supplier, and is  
 * protected under applicable copyright laws. All rights are reserved.  
 * Any use in violation of the foregoing restrictions may subject the  
 * user to criminal sanctions under applicable laws, as well as to  
 * civil liability for the breach of the terms and conditions of this  
 * license. 
 * 
 * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,  
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED  
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,  
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR  
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. 
 * 
 * 
 * This file contains Explicit messaging support for the Connection Object  
 * described in Section 5-4 and Chapter 7 of Volume 1 of the DeviceNet  
 * specification. 
 *  
 * 
 * 
 * Author               Date        Comment 
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
 * Ross Fosler			04/28/03	...	 
 *  
 *****************************************************************************/ 
 
#include	"dnet.def"			// Global definitions file 
 
#include 	"typedefs.h" 
 
#include	"conn.h"			// Connection prototypes and symbols 
 
#include	"services.h"		// Service codes 
#include	"errors.h"			// Error codes 
#include	"class.h"			// Class codes 
 
#include	"route.h"			// Global symbols defined by the router 
#include	"dnet.h"			// DeviceNet prototypes and symbols 
#include	"frag.h"			// Fragmentation control 
 
#include	"CAN.h"				// CAN driver 
 
 
#define		_FRAG_SUCCESS	0 
#define		_FRAG_TOO_MUCH	1 
 
 
 
 
 
#define		RXFLAG_FIRST_FRAG		b0 
#define		TXFLAG_SEND_ACK			b0 
#define		TXFLAG_ACK_STAT			b1 
#define		TXFLAG_TX_START			b2 
#define		TXFLAG_TX_TIMER_EN		b3 
#define		TXFLAG_TX_AGAIN			b4 
#define		TXFLAG_TX_FIN			b5 
 
 
 
#pragma 	udata 
/********************************************************************* 
 * Connection related variables 
 ********************************************************************/ 
CONN_EXPL 		uConn1; 
 
unsigned char	uConn1RxBuffer[CONN_EXPLICIT_RX_SIZE]; 
unsigned char	uConn1TxBuffer[CONN_EXPLICIT_TX_SIZE]; 
 
 
 
/********************************************************************* 
 * Function:        unsigned char _Conn1Create(void) 
 * 
 * PreCondition:    none 
 * 
 * Input:       	none	 
 *                   
 * Output:      	handle to connection 
 * 
 * Side Effects:    none 
 * 
 * Overview:        Returns a handle to the connection  
 * 
 * Note:            none 
 ********************************************************************/ 
unsigned char _Conn1Create(void) 
{ 
	//Initialize the connection attributes 
	uConn1.attrib.state = _STATE_ESTABLISHED; 
	uConn1.attrib.produced_cid.bytes.MSB = uDNet.MACID | 0x80; 
	uConn1.attrib.produced_cid.bytes.LSB = 0x60; 
	uConn1.attrib.consumed_cid.bytes.MSB = uDNet.MACID | 0x80;  
	uConn1.attrib.consumed_cid.bytes.LSB = 0x80; 
	uConn1.attrib.expected_packet_rate.word = 2500; 
	uConn1.attrib.wdt_action = _WDT_ACTION_DEFERRED; 
	 
	_establishFlags.bits.expl = 1; 
	_existentFlags.bits.expl = 1; 
	 
	// Setup the pointer and other info for the receiving side 
	uConn1.rx.pMsg = uConn1RxBuffer; 
	uConn1.rx.lenMax = CONN_EXPLICIT_RX_SIZE; 
	uConn1.rx.fragFlags.byte = 0; 
	uConn1.rx.oldFrag = 0; 
	 
	// Setup the pointer and other info for the transmitting side 
	uConn1.tx.pMsg = uConn1TxBuffer; 
	uConn1.tx.lenMax = CONN_EXPLICIT_TX_SIZE; 
	uConn1.tx.fragFlags.byte = 0; 
	uConn1.tx.oldFrag = 0; 
 
	// Put 10000 or (rate)x(4), whichever is greater 
	uConn1.timer.word = (uConn1.attrib.expected_packet_rate.word << 2); 
	if (uConn1.timer.word < 10000) uConn1.timer.word = 10000; 
	 
	// Set the time 
	uConn1.ack_tmr.word = EXPLICIT_ACK_TIMER;		 
			 
	//Issue a request to start receiving the CID 
	CANSetFilter(uConn1.attrib.consumed_cid.word); 
	return (1); 
} 
 
 
/********************************************************************* 
 * Function:        unsigned char _Conn1Close(void) 
 * 
 * PreCondition:     
 * 
 * Input:       	none		 
 *                   
 * Output:      	status of the close 
 * 
 * Side Effects:     
 * 
 * Overview:        Closes the specified connection  
 * 
 * Note:            None 
 ********************************************************************/ 
unsigned char _Conn1Close(void) 
{	 
	// Transition to the non-existent state 
	uConn1.attrib.state = _STATE_NON_EXISTENT; 
	 
	_establishFlags.bits.expl = 0; 
	_existentFlags.bits.expl = 0; 
	 
	// Issue a request to the driver to stop receiving the message 
	CANClrFilter(uConn1.attrib.consumed_cid.word); 
 
	return(1); 
} 
 
 
 
 
 
/********************************************************************* 
 * Function:        void _Conn1TimerEvent(void) 
 * 
 * PreCondition:     
 * 
 * Input:       	none		 
 *                   
 * Output:      	none 
 * 
 * Side Effects:     
 * 
 * Overview:        Update timer and process any timer events. 
 * 
 * Note:            None 
 ********************************************************************/ 
void _Conn1TimerEvent(void) 
{		 
	// Process the watchdog if the packet rate is other than 0 
	if (uConn1.attrib.expected_packet_rate.word) 
	{ 
		// Adjust the time 
		uConn1.timer.word -= TICK_RESOLUTION; 
 
		// If the wdt expires then change the state of the connection 
		if (uConn1.timer.word == 0)  
		{ 
			// Auto delete the connection 
			if (uConn1.attrib.wdt_action == _WDT_ACTION_AUTO_DELETE) 
			{  
				uConn1.attrib.state = _STATE_NON_EXISTENT; 
			} 
			else  
			 
			// Deferred delete (full release is determined outside  
			// of this instance) 
			if (uConn1.attrib.wdt_action == _WDT_ACTION_DEFERRED)  
			{ 
				uConn1.attrib.state = _STATE_DEFERED_DELETE; 
			} 
		} 
	} 
 
#if	FRAGMENTATION_ACK 
	// Process fragmentation timer for acknowledged transmission 
	if (uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN == 1) 
	{ 
		// Adjust ack timer 
		uConn1.ack_tmr.word -= TICK_RESOLUTION; 
 
		// If the ack timer expires then change the frag state 
		if (uConn1.ack_tmr.word == 0) 
		{	 
			// Disable the timer 
			uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 0; 
			 
			// Reset the time 
			uConn1.ack_tmr.word = EXPLICIT_ACK_TIMER; 
 
			// If a resend has been requested 
			if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1) 
			{ 
				// Kill the message 
				// Reset the transmit state 
				uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 0; 
				uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 0; 
				uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 0; 
 
				// Set flag indicating completion 
				_txFinFlags.bits.expl = 1; 
			} 
			else 
			{ 
				// Issue a resend 
				uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 1; 
				_txFlag.bits.expl = 1; 
			} 
		} 
	} 
#endif 
} 
 
 
 
 
/********************************************************************* 
 * Function:        void _Conn1RxEvent(void) 
 * 
 * PreCondition:     
 * 
 * Input:       	none	 
 *                   
 * Output:      	none 
 * 
 * Side Effects:     
 * 
 * Overview:        Process data for this connection. 
 * 
 * Note:            This event occures when data has been received 
 *					for this connection instance. 
 ********************************************************************/ 
void _Conn1RxEvent(void) 
{ 
	BYTE header, service, frag, count, type, len; 
	unsigned char *pRxData; 
 
	// Set the size of classId depending on what has been specified 
	#if (CLASS_WIDTH_16BIT) 
	UINT classId; 
	#else 
	BYTE classId; 
	#endif 
	 
	// Get the pointer to the buffer 
	pRxData = CANGetRxDataPtr(); 
	len.byte = CANGetRxCnt(); 
	 
	// Extract the header	 
	header.byte = *pRxData;  
		 
#if	FRAGMENTATION_ACK				 
	// If fragmented 
	if (header.bits.b7) 
	{ 
		// Process only if there is sufficient data to process the connection 
		if (len.byte > 2) 
		{ 
			// Point to the frag byte and copy it 
			pRxData++; 
			frag.byte = *pRxData;  
			 
			// Point to the service 
			pRxData++;  
			 
			// Get the fragment type and count 
			type.byte = frag.byte & 0xC0; 
			count.byte = frag.byte & 0x3F; 
		 
			// If the header MAC equals the allocated MasterMACID then  
			// process the message fragment	 
			if (((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0) 
			{			 
				// Remember the header 
				uConn1.rx.header = header.byte;  
					 
				// Process the fragment 
				switch (type.byte) 
				{ 
					// Received first fragment 
					case 0x00: 
						// The first fragment must always have a frag byte of 0 
						if (frag.byte == 0) 
						{ 
							// Copy the fragment to the buffer 
							CANGetRxDataTyp2(uConn1.rx.pMsg + 1); 
							 
							// Store the header 
							*uConn1.rx.pMsg = header.byte; 
				 
							// Adjust the length minus the fragment control byte 
							uConn1.rx.len = len.byte - 1; 
												 
							// Request to issue an ACK with status	 
							uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1; 
							uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0; 
							_txFlag.bits.expl = 1; 
											 
							// Reset the old fragment 
							uConn1.rx.oldFrag = 0; 
				 
							// Indicate the first fragment has been received 
							uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 1; 
						} 
						break; 
						 
					// Received a middle or last fragment 
					case 0x40: 
					case 0x80: 
						// If this frag is the same as the previous then re-ack 
						if (uConn1.rx.oldFrag == frag.byte) 
						{ 
							// Set the status & request the hardware to send the ACK 
							uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1; 
							uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0; 
							_txFlag.bits.expl = 1; 
						} 
						else 
					 
						// Continue if the first fragment has been received 
						if (uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG) 
						{						 
							// Process the current fragment 
							if (((uConn1.rx.oldFrag + 1) & 0x3F) == count.byte) 
							{ 
								// if the buffer is large enough 
								if ((uConn1.rx.len + (len.byte - 1)) < uConn1.rx.lenMax) 
								{ 
						 
									// Copy this fragment to the buffer 
									CANGetRxDataTyp2(uConn1.rx.pMsg + uConn1.rx.len); 
					 
									// Store the length minus the fragment control byte and header 
									uConn1.rx.len += (len.byte - 2); 
								 
									// Save the current fragment information 
									uConn1.rx.oldFrag = frag.byte; 
									 
									// If this the last fragment in the sequence 
									if (type.byte == 0x80) 
									{ 
										// Indicate message has been received 
										_rxFlag.bits.expl = 1; 
									} 
								 
									// Set the status & request the hardware to send the ACK				 
									uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1; 
									uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0; 
									_txFlag.bits.expl = 1; 
								} 
							 
								//else send an error ack indicating too much data		 
								else 
								{ 
									// Set the status & request the hardware to send the ACK				 
									uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1; 
									uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 1; 
									_txFlag.bits.expl = 1; 
								 
									// Reset to the initial state 
									uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0; 
								} 
							} 
						 
							// Toss the fragment and reset to the first state 
							else 
							{ 
								// Reset to the initial state 
								uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0; 
							} 
						} 
					 
						// Fragment not expected 
						else 
						{ 
							// Reset to the initial state	 
							uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;	 
						} 
						break; 
						 
										 
					// Received an ACK 
					case 0xC0: 
						// Process ack if expecting it 
						if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1) 
						{ 
							// Stop the acknowledge timer if it was running 
							uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 0; 
 
							// Reset the retry flag if it was set 
							uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 0; 
 
							// If the last transmission has been sent 
							if (uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN == 1) 
							{ 
								// Reset the transmit state 
								uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 0; 
								uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 0; 
							} 
							else 
							{ 
								// Start up the next transmission 
								_txFlag.bits.expl = 1; 
							} 
						} 
						break; 
					} 
							 
							 
							 
				 
				// Put the connection into the established state 
				uConn1.attrib.state = _STATE_ESTABLISHED; 
				_establishFlags.bits.expl = 1; 
				 
				// Reset the connection wdt 
				uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2; 
			} 
		} 
	} 
#else 
	// If fragmented 
	if (header.bits.b7) 
	{ 
		// Process only if there is sufficient data to process the connection 
		if (len.byte > 2) 
		{ 
			// If the header MAC equals the allocated MasterMACID then  
			// process the message fragment	 
			if (((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0) 
			{ 
				// Request to issue an ACK with error status	 
				uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1; 
				uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 1; 
				_txFlag.bits.expl = 1; 
			} 
		} 
	} 
#endif 
 
	// else process a non-fragmented message 
	else 
	{  
		// Process only if there is sufficient data to process the connection 
		if (len.byte > 1) 
		{ 
			// Extract the service ID   
			service.byte = *(pRxData + 1); 
		 
			// If the header MAC equals the allocated MasterMACID or if the release 
			// connection service is requested then process the message. 
			// (refer to section 5-5.4.2) 
			#if (CLASS_WIDTH_16BIT) 
			classId.bytes.LSB = *(pRxData + 2); 
			classId.bytes.MSB = *(pRxData + 3);	 
			if (((classId.word == CLASS_DEVICENET) && (service.byte == SRVS_RELEASE_CONN)) || 
				(header.byte ^ uDNet.AllocInfo.MasterMACID & 0x3F) == 0) 
			#else 
			classId.byte = *(pRxData + 2); 
			if (((classId.byte == CLASS_DEVICENET) && (service.byte == SRVS_RELEASE_CONN)) || 
				(header.byte ^ uDNet.AllocInfo.MasterMACID & 0x3F) == 0) 
			#endif 
			{ 
				// Remember the header 
				uConn1.rx.header = header.byte;;  
				 
				// Get the count		 
				uConn1.rx.len = CANGetRxCnt(); 
		 
				// Copy the message to the connection buffer 
				CANGetRxDataTyp0(uConn1RxBuffer); 
			 
				// Indicate message has been received (located in conn.c)	 
				_rxFlag.bits.expl = 1; 
		 
				// Put the connection into the established state 
				uConn1.attrib.state = _STATE_ESTABLISHED; 
				_establishFlags.bits.expl = 1; 
				 
				// Reset the connection wdt 
				uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2; 
			} 
		} 
	} 
	 
	// Release the hardware to continue receiving 
	CANRead(); 
} 
 
 
 
  
/********************************************************************* 
 * Function:        void _Conn1TxOpenEvent(void) 
 * 
 * PreCondition:    none 
 * 
 * Input:       	none	 
 *                   
 * Output:      	none 
 * 
 * Side Effects:    none 
 * 
 * Overview:        Process 
 * 
 * Note:            This event occurs when the buffer is available  
 *					for this connection instance to transmit. 
 ********************************************************************/ 
void _Conn1TxOpenEvent(void) 
{ 
	BYTE header; 
	unsigned char *pTxData; 
	 
	// Get the pointer to the CAN transmit buffer 
	pTxData = CANGetTxDataPtr(); 
 
	// If acknowledge requested then force fragment processing 
	if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1) 
	{ 
		header.bits.b7 = 1; 
	} 
	 
	// Else get the header from top level 
	else 
	{ 
		header.byte = *uConn1TxBuffer; 
	} 
	 
#if	FRAGMENTATION_ACK 
	// If fragmented 
	if (header.bits.b7) 
	{ 
		// If in the send ack state as a result of a receive then 
		if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1) 
		{ 
			// Copy the header and the fragment count (header should be  
			// the same as the received header) 
			*pTxData = uConn1.rx.header; pTxData++; 
			*pTxData = uConn1.rx.oldFrag | 0xC0; pTxData++; 
 
			// Send a success ack  
			if (uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT == 0) 
			{ 
				*pTxData = _FRAG_SUCCESS; 
			} 
			// or send an error ack 
			else 
			{ 
				*pTxData = _FRAG_TOO_MUCH; 
			} 
			 
			// Set the length of the message 
			CANPutTxCnt(3); 
		}	 
		else  
 
		// If a resend has been requested 
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1) 
		{ 
			// Copy the header 
			*pTxData = *uConn1TxBuffer; pTxData++; 
			 
			// Copy the last fragment 
			*pTxData = uConn1.tx.oldFrag; 
			 
			// Copy 6 bytes of the packet 
			CANPutTxDataTyp2(uConn1TxBuffer + uConn1.tx.index); 
		} 
		else 
		 
		// If the first fragmented transmit progress has been started already 
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1) 
		{ 
			// Copy the header 
			*pTxData = *uConn1TxBuffer; pTxData++; 
			 
			// Adjust the fragment byte 
			uConn1.tx.oldFrag++; 
			 
			// Adjust the index 
			uConn1.tx.index += 7; 
			 
			// If last fragment 
			if (uConn1.tx.len < 7) 
			{ 
				// Indicate the last fragment has been queued to send 
				uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 1; 
				 
				// Set the type 
				uConn1.tx.oldFrag = (uConn1.tx.oldFrag & 0x3F) | 0xC0;   
				 
				// Set the length of the message 
				CANPutTxCnt(uConn1.tx.len + 2); 
				 
				// Adjust the length 
				uConn1.tx.len = 0; 
			} 
			 
			// Middle fragment 
			else 
			{ 
				// Set the type 
				uConn1.tx.oldFrag = (uConn1.tx.oldFrag & 0x3F) | 0x80; 
				 
				// Set the length of the message 
				CANPutTxCnt(8); 
				 
				// Adjust the length 
				uConn1.tx.len -= 6; 
			} 
			 
			// Copy the fragment info 
			*pTxData = uConn1.tx.oldFrag; 
			 
			// Copy 6 bytes of the packet 
			CANPutTxDataTyp2(uConn1TxBuffer + uConn1.tx.index); 
		} 
 
		// Transmit has not been started, so que the first message 
		else 
		{ 
			// Copy the header 
			*pTxData = *uConn1TxBuffer; pTxData++; 
			 
			// Set the frag byte to first fragment  
			*pTxData = uConn1.tx.oldFrag = 0; 
			 
			// Set the index 
			uConn1.tx.index = 1; 
			 
			// Copy the first 6 bytes of the packet 
			CANPutTxDataTyp2(uConn1TxBuffer + 1); 
				 
			// Adjust the length by 7, i.e. header and 6 data bytes 
			uConn1.tx.len = uConn1.tx.len - 7; 
					 
			// Set the length of the message 
			CANPutTxCnt(8); 
			 
			// Indicate the first message has been started 
			uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 1; 
		} 
	} 
#else 
	// If fragmented 
	if (header.bits.b7) 
	{ 
		// If in the send ack state as a result of a receive then 
		if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1) 
		{ 
			// Copy the header and the fragment count (header should be  
			// the same as the received header) 
			*pTxData = uConn1.rx.header; pTxData++; 
			*pTxData = uConn1.rx.oldFrag | 0xC0; pTxData++; 
 
			// Send a success ack  
			if (uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT == 0) 
			{ 
				*pTxData = _FRAG_SUCCESS; 
			} 
			// or send an error ack 
			else 
			{ 
				*pTxData = _FRAG_TOO_MUCH; 
			} 
			 
			// Set the length of the message  
			CANPutTxCnt(3); 
		} 
		else 
		{ 
			//Clear the transmit flag to open access to the write buffer 
			_txFlag.bits.expl = 0; 
			return; 
		} 
	} 
#endif   
 
 
	// else process a non-fragmented message 
	else 
	{ 
		// Copy the message to the hardware buffer 
		CANPutTxDataTyp0(uConn1TxBuffer); 
		 
		// Set the length of the message 
		CANPutTxCnt(uConn1.tx.len); 
	}	 
	 
	//Clear the transmit flag to open access to the write buffer 
	_txFlag.bits.expl = 0; 
	// Request the hardware to queue the message to send 
	CANSend(1); 
} 
 
 
/********************************************************************* 
 * Function:        void _Conn1TxEvent(void) 
 * 
 * PreCondition:     
 * 
 * Input:       	none 
 *                   
 * Output:      	none 
 * 
 * Side Effects:     
 * 
 * Overview:        Process data for this connection. 
 * 
 * Note:            This event occurs when the buffer has successfully 
 *					placed the requested data on the bus. 
 ********************************************************************/ 
void _Conn1TxEvent(void) 
{ 
	BYTE header; 
	unsigned char *pTxData; 
	 
		  
	// If acknowledge requested then force fragment processing 
	if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1) 
	{ 
		header.bits.b7 = 1; 
	} 
	 
	// Else get the header from top level 
	else 
	{ 
		header.byte = *uConn1TxBuffer; 
	}	 
		 
	// If fragmented 
	if (header.bits.b7) 
	{ 
		// If in the send ack state as a result of a receive then 
		if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1) 
		{ 
			// Remove the send ack request 
			uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 0; 
		} 
		 
	#if	FRAGMENTATION_ACK 
		else 
 
		// If a resend has been requested 
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1) 
		{ 
			// Start the acknowledge timer 
			uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 1; 
		} 
		else 
 
		// If the last transmission has been sent 
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN == 1) 
		{ 
			// Set flag indicating all data has been placed on the bus 
			_txFinFlags.bits.expl = 1; 
		} 
		else 
 
		// If the first fragmented transmit progress has been started already 
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1) 
		{ 
			// Start the acknowledge timer 
			uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 1; 
		} 
	#endif 
	} 
	 
	// Not fragmented 
	else 
	{ 
		// Set flag indicating data has been placed on the bus 
		_txFinFlags.bits.expl = 1; 
	} 
} 
 
 
 
 
 
/********************************************************************* 
 * Function:        unsigned char _Conn1ExplicitEvent(void) 
 * 
 * PreCondition:     
 * 
 * Input:       	none	 
 *                   
 * Output:      	status 
 * 
 * Side Effects:     
 * 
 * Overview:        Handle explicit messaging 
 * 
 * Note:            None 
 ********************************************************************/ 
unsigned char _Conn1ExplicitEvent(void) 
{ 
	switch(mRouteGetServiceID()) 
   	{ 
   		case SRVS_GET_ATTRIB_SINGLE: 
   			return (_Conn1GetAttrib()); 
   		case SRVS_SET_ATTRIB_SINGLE: 
   			return (_Conn1SetAttrib()); 
   	   	default: 
   			mRoutePutError(ERR_SERVICE_NOT_SUPPORTED); 
   			break; 
   	} 
		 
	return (1); 
} 
 
 
/********************************************************************* 
 * Function:        unsigned char _Conn1GetAttrib() 
 * 
 * PreCondition:     
 * 
 * Input:       	none 
 *                   
 * Output:      	status 
 * 
 * Side Effects:     
 * 
 * Overview:        Handle explicit messaging 
 * 
 * Note:            None 
 ********************************************************************/ 
unsigned char _Conn1GetAttrib(void) 
{ 
	UINT	work; 
 
	switch (mRouteGetAttributeID()) 
	{ 
		case	_ATTRIB_STATE: 
			mRoutePutByte(uConn1.attrib.state); 
			break; 
		case	_ATTRIB_INSTANCE_TYPE: 
			mRoutePutByte(0); 
			break; 
		case	_ATTRIB_CLASS_TRIGGER: 
			mRoutePutByte(0x83); 
			break; 
		case 	_ATTRIB_PRODUCED_CID: 
			work.word = (uConn1.attrib.produced_cid.word >> 5); 
			mRoutePutByte(work.bytes.LSB); 
			mRoutePutByte(work.bytes.MSB); 
			break; 
		case	_ATTRIB_CONSUMED_CID: 
			work.word = (uConn1.attrib.consumed_cid.word >> 5); 
			mRoutePutByte(work.bytes.LSB); 
			mRoutePutByte(work.bytes.MSB); 
			break;	 
		case 	_ATTRIB_INITIAL_COMM_CHAR: 
			mRoutePutByte(0x21); 
			break; 
		case	_ATTRIB_PRODUCED_CONN_SIZE: 
			mRoutePutByte(uConn1.tx.lenMax); 
			mRoutePutByte(0); 
			break; 
		case	_ATTRIB_CONSUMED_CONN_SIZE: 
			mRoutePutByte(uConn1.rx.lenMax); 
			mRoutePutByte(0); 
			break; 
		case	_ATTRIB_EXPECTED_RATE: 
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.LSB); 
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.MSB); 
			break; 
		case	_ATTRIB_WDT_ACTION: 
			mRoutePutByte(uConn1.attrib.wdt_action); 
			break; 
		case	_ATTRIB_PRODUCED_CONN_PATH_LEN: 
		case	_ATTRIB_CONSUMED_CONN_PATH_LEN: 
			mRoutePutByte(0); 
			mRoutePutByte(0); 
			break; 
		case	_ATTRIB_PRODUCED_CONN_PATH: 
		case	_ATTRIB_CONSUMED_CONN_PATH: 
			break; 
		default: 
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED); 
			break; 
	} 
	return(1); 
} 
 
 
 
 
/********************************************************************* 
 * Function:        unsigned char _Conn1SetAttrib(void) 
 * 
 * PreCondition:     
 * 
 * Input:       	none 
 *                   
 * Output:      	status 
 * 
 * Side Effects:     
 * 
 * Overview:        Handle explicit messaging 
 * 
 * Note:            None 
 ********************************************************************/ 
unsigned char _Conn1SetAttrib(void) 
{ 
	unsigned char 	work; 
 
	switch (mRouteGetAttributeID()) 
	{	 
		case	_ATTRIB_EXPECTED_RATE: 
			// Read in the requested packet rate 
			uConn1.attrib.expected_packet_rate.bytes.LSB = mRouteGetByte(); 
			uConn1.attrib.expected_packet_rate.bytes.MSB = mRouteGetByte(); 
 
			// Get the ls bits 
			work = uConn1.attrib.expected_packet_rate.bytes.LSB & (TICK_RESOLUTION - 1); 
 
			// Remove the ls bits from desired resolution 
			uConn1.attrib.expected_packet_rate.bytes.LSB &= (~(TICK_RESOLUTION - 1)); 
			 
			// Round up if necessary 
			if (work) uConn1.attrib.expected_packet_rate.word += (TICK_RESOLUTION); 
 
			// Return the value actually used 
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.LSB); 
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.MSB); 
 
			// Set the timer 4x (section 5-4.4.2) 
			uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2;  
			break; 
			 
		case	_ATTRIB_WDT_ACTION: 
			work = mRouteGetByte(); 
			if ((work == _WDT_ACTION_DEFERRED) || (work == _WDT_ACTION_AUTO_DELETE)) 
			{ 
				uConn1.attrib.wdt_action = work; 
			} 
			else 
			{ 
				mRoutePutError(ERR_INVALID_ATTRIB_VALUE); 
			} 
			break; 
		 
 
		case	_ATTRIB_PRODUCED_CONN_SIZE: 
		case	_ATTRIB_CONSUMED_CONN_SIZE: 
		case	_ATTRIB_STATE: 
		case	_ATTRIB_INSTANCE_TYPE: 
		case	_ATTRIB_CLASS_TRIGGER: 
		case 	_ATTRIB_PRODUCED_CID: 
		case	_ATTRIB_CONSUMED_CID: 
		case 	_ATTRIB_INITIAL_COMM_CHAR: 
		case	_ATTRIB_PRODUCED_CONN_PATH_LEN: 
		case	_ATTRIB_PRODUCED_CONN_PATH: 
		case	_ATTRIB_CONSUMED_CONN_PATH_LEN: 
		case	_ATTRIB_CONSUMED_CONN_PATH: 
			mRoutePutError(ERR_ATTRIB_NOT_SETTABLE); 
			break; 
			 
		default: 
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED); 
			break; 
	} 
	return(1); 
}