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


/***************************************************************************** 
 * 
 * Microchip DeviceNet Stack (Connection Object Fragmentation Source) 
 * 
 ***************************************************************************** 
 * FileName:        frag.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 unacknowledged fragmentation support. Refer to  
 * section 4-4 of Volume 1 of the DeviceNet specification. 
 *  
 * 
 * 
 * Author               Date        Comment 
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
 * Ross Fosler			04/28/03	...	 
 *  
 *****************************************************************************/ 
 
 
 
 
#include	"dnet.def"			// Global definitions file 
#include 	"typedefs.h" 
 
#if FRAGMENTATION_UNACK 
 
#include	"conn.h"			// Internal definitions 
 
#include	"services.h"		// Service codes 
#include	"errors.h"			// Error codes 
#include	"class.h"			// Class codes 
 
#include	"dnet.h"			// Global symbols defined by the DeviceNet Obj 
#include	"CAN.h"				// CAN driver 
 
 
 
 
 
 
#define		_STATE_NOACK_PRODUCE_FIRST_FRAG			0 
#define		_STATE_NOACK_PRODUCE_MID_FRAG			1 
#define		_STATE_NOACK_PRODUCE_LAST_FRAG			2 
 
#define		_STATE_NOACK_CONSUME_WAIT_FOR_FIRST_FRAG	0 
#define		_STATE_NOACK_CONSUME_WAIT_FOR_FRAG			1 
 
 
// Control flags for fragmented processing 
//	<TX/RX><ACK/IO><RES><RES><RES><TXLOCK><ERR><FIN> 
 
#if USE_ACCESS == TRUE 
#pragma	udata access _A_FRAG_REGISTERS 
#endif 
  
NEAR FRAG _aFrag; 
NEAR UINT _timer; 
 
 
 
 
#pragma	udata 
 
/********************************************************************* 
 * Function:        void _FragNoAckConsume(void) 
 * 
 * PreCondition: 	The fragment structure must be loaded with the  
 *					last known state of the calling connection.   
 * 
 * Input:       	none 
 *                   
 * Output:      	none 
 * 
 * Side Effects:    _aFrag is updated. 
 * 
 * Overview:      	This function handles unacknowledged reception 
 *					of fragmented data. 
 * 
 * Note:            This function only receives data and does not  
 *					free the CAN driver to receive. It is up to the 
 *					calling function to release the hardware to  
 *					receive data. 
 ********************************************************************/ 
void _FragNoAckConsume(void) 
{ 
	unsigned char frag, type, len; 
	unsigned char *pRxData; 
	 
	// Get a pointer to the buffer 
	pRxData = CANGetRxDataPtr(); 
	 
	// Get the fragmentation control byte then point to the data 
	frag = *pRxData; //pRxData++; 
	 
	// Get the fragment type 
	type = frag & 0xC0; 
	 
	switch (type) 
	{ 
		// First fragment received 
		case 0x00: 
			// Is this the first or only fragment 
			if (frag == 0x3F || frag == 0) 
			{ 
				// Store the length minus the fragment control byte 
				_aFrag.rx.len = CANGetRxCnt() - 1; 
				 
				// Copy this fragment to the buffer 
				CANGetRxDataTyp1(_aFrag.rx.pMsg); 
			//	*((_MSG_DATA_IO_FRAG *)_aFrag.rx.pMsg) = *((_MSG_DATA_IO_FRAG *)pRxData); 
										 
				// Is this the only fragment		 
				if (frag == 0x3F) 
				{ 
					// Set the finish flag 
					_aFrag.rx.fragFlags.bits.b0 = 1; 
				} 
				else 
				{ 
					// Change the state 
					_aFrag.rx.fragState = _STATE_NOACK_CONSUME_WAIT_FOR_FRAG; 
					_aFrag.rx.oldFrag = 0; 
				}  
			} 
			else 
			{ 
				// This is an error 
				_aFrag.rx.fragFlags.bits.b1 = 1; 
			} 
			break; 
		 
		// Middle or last fragment 
		case 0x40: 
		case 0x80: 
			// Has the first fragment been received 
			if (_aFrag.rx.fragState == _STATE_NOACK_CONSUME_WAIT_FOR_FRAG) 
			{ 
				// Is this the next fragment in the sequence 
				if (((frag ^ (_aFrag.rx.oldFrag + 1)) & 0x3F) == 0) 
				{ 
					// Remember the fragment control byte 
					_aFrag.rx.oldFrag = frag; 
		 
					// Copy the length 
					len = _aFrag.rx.len; 
		 
					// Adjust the length  
					_aFrag.rx.len += (CANGetRxCnt() - 1); 
					 
					// Check the size of the buffer 
					if (_aFrag.rx.len <= _aFrag.rx.lenMax) 
					{		 
						// Copy this fragment to the buffer 
						CANGetRxDataTyp1(_aFrag.rx.pMsg + len); 
			//			*((_MSG_DATA_IO_FRAG *)(_aFrag.rx.pMsg + len)) =  
			//				*((_MSG_DATA_IO_FRAG *)pRxData); 
							 
						// Is this the last fragment 
						if (type == 0x80) 
						{ 
							// Set the finish flag 
							_aFrag.rx.fragFlags.bits.b0 = 1; 
						 
							// Change to the beginning state 
							_aFrag.rx.fragState = _STATE_NOACK_CONSUME_WAIT_FOR_FIRST_FRAG; 
						} 
					} 
					 
					// Too much data to copy to the buffer 
					else 
					{ 
						// This is an error  
						_aFrag.rx.fragFlags.bits.b1 = 1; 
					 
						// Go back to the first fragment 
						_aFrag.rx.fragState = _STATE_NOACK_CONSUME_WAIT_FOR_FIRST_FRAG; 
					} 
				} 
				 
				// Received a fragment out of sequence 
				else 
				{ 
					// This is an error  
					_aFrag.rx.fragFlags.bits.b1 = 1; 
					 
					// Go back to the first fragment 
					_aFrag.rx.fragState = _STATE_NOACK_CONSUME_WAIT_FOR_FIRST_FRAG; 
				} 
			} 
			break; 
		 
		// Received an acknowledge fragment, which is invalid for this  
		// type of fragmentation 
		case 0xC0: 
			// This is an error  
			_aFrag.rx.fragFlags.bits.b1 = 1; 
			 
			// Go back to the first fragment 
			_aFrag.rx.fragState = _STATE_NOACK_CONSUME_WAIT_FOR_FIRST_FRAG; 
			break; 
	} 
} 
 
 
 
/********************************************************************* 
 * Function:        void _FragNoAckProduce(void) 
 * 
 * PreCondition:    The fragment structure must be loaded with the  
 *					last known state of the calling connection. 
 * 
 * Input:       	none	 
 *                   
 * Output:      	none 
 * 
 * Side Effects:    _aFrag is updated. 
 * 
 * Overview:        This function handles unacknowledged transmission 
 *					of fragmented data.   
 * 
 * Note:            This function does not issue any requests to the  
 *					driver to send data. It is up to the calling  
 *					to issue the transmit request. 
 ********************************************************************/ 
void _FragNoAckProduce(void) 
{ 
	unsigned char *pTxData; 
	 
	// Get a pointer to the buffer 
	pTxData = CANGetTxDataPtr(); 
		 
	switch (_aFrag.tx.fragState) 
	{ 
		// Send an unacknowledged first fragment 
		case _STATE_NOACK_PRODUCE_FIRST_FRAG: 
				 
			// If the whole message is less than the max fragment size 
			// then send the only fragment 
			if (_aFrag.tx.len < 8) 
			{ 
				// Set the fragment control byte and point to the next data location 
				*pTxData = 0x3F; pTxData++; 
			 
				// Copy this fragment to the transmit buffer 
				CANPutTxDataTyp1(_aFrag.tx.pMsg); 
	//			*((_MSG_DATA_IO_FRAG *)pTxData) =  
	//				*((_MSG_DATA_IO_FRAG *)(_aFrag.tx.pMsg)); 
					 
				// Set the length of the data to send 
				CANPutTxCnt(_aFrag.tx.len + 1); 
				 
				// Indicate the process is finished 
				_aFrag.tx.fragFlags.bits.b0 = 1;					 
			} 
			 
			// Else send the first fragment of the whole message 
			else 
			{ 
				// Set the fragment control byte and point to the next data location 
				*pTxData = _aFrag.tx.oldFrag = 0; //pTxData++; 
								 
				// Copy this fragment to the transmit buffer 
				CANPutTxDataTyp1(_aFrag.tx.pMsg); 
		//		*((_MSG_DATA_IO_FRAG *)pTxData) =  
		//			*((_MSG_DATA_IO_FRAG *)(_aFrag.tx.pMsg)); 
					 
				// Adjust the index 
				_aFrag.tx.index = 7; 
				 
				// Set the length of the data to send 
				CANPutTxCnt(8); 
								 
				// Set the next state 
				if ((_aFrag.tx.len - _aFrag.tx.index) > 8) 
					_aFrag.tx.fragState = _STATE_NOACK_PRODUCE_MID_FRAG; 
				else 
					_aFrag.tx.fragState = _STATE_NOACK_PRODUCE_LAST_FRAG; 
			} 
			break; 
			 
		// Send a middle fragment 
		case _STATE_NOACK_PRODUCE_MID_FRAG: 
		 
			// Set the fragment control byte and point to the next data location 
			*pTxData = _aFrag.tx.oldFrag = ((_aFrag.tx.oldFrag + 1) & 0x3F) | 0x40;  
		//	pTxData++; 
		 
			// Copy this fragment to the transmit buffer 
			CANPutTxDataTyp1(_aFrag.tx.pMsg + _aFrag.tx.index); 
	//		*((_MSG_DATA_IO_FRAG *)pTxData) =  
	//			*((_MSG_DATA_IO_FRAG *)(_aFrag.tx.pMsg + _aFrag.tx.index)); 
				 
			// Adjust the index 
			_aFrag.tx.index += 7; 
			 
			// Set the length of the data to send 
			CANPutTxCnt(8); 
						 
			// Set the next state 
			if ((_aFrag.tx.len - _aFrag.tx.index) > 8) 
				_aFrag.tx.fragState = _STATE_NOACK_PRODUCE_MID_FRAG; 
			else 
				_aFrag.tx.fragState = _STATE_NOACK_PRODUCE_LAST_FRAG; 
		 
			break; 
			 
		// Send the last fragment 
		case _STATE_NOACK_PRODUCE_LAST_FRAG: 
		 
			// Set the fragment control byte and point to the next data location 
			*pTxData = _aFrag.tx.oldFrag = ((_aFrag.tx.oldFrag + 1) & 0x3F) | 0x80;  
	//		pTxData++; 
		 
			// Copy this fragment to the transmit buffer 
			CANPutTxDataTyp1(_aFrag.tx.pMsg + _aFrag.tx.index); 
	//		*((_MSG_DATA_IO_FRAG *)pTxData) =  
	//			*((_MSG_DATA_IO_FRAG *)(_aFrag.tx.pMsg + _aFrag.tx.index)); 
			 
			// Set the length of the data to send 
			CANPutTxCnt(_aFrag.tx.len - _aFrag.tx.index + 1); 
			 
			// Indicate the process is finished 
			_aFrag.tx.fragFlags.bits.b0 = 1;	 
					 
		// Fallout state, should never get here except through the last fragment 
		default: 
			_aFrag.tx.fragState = _STATE_NOACK_PRODUCE_FIRST_FRAG; 
	} 
} 
 
 
 
 
#endif