
/*****************************************************************************
 *
 *              Microchip DeviceNet Stack (DeviceNet Object)
 *
 *****************************************************************************
 * FileName:        dnet.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 the DeviceNet object described in section 5-5 of 
 * volume 1 of the DeviceNet specification.
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Ross Fosler			04/03/03	...	
 * 
 *****************************************************************************/

#include	"dnet.def"			// Global definitions file
#include 	"typedefs.h"

#include	"dnet.h"			// Internal prototypes
#include	"usrdnet.h"			// External prototypes

#include	"services.h"		// Service codes
#include	"errors.h"			// Error codes
#include	"class.h"			// Class codes

#include	"conn.h"
#include	"route.h"			// Global symbols defined by the router



/*********************************************************************
 * DeviceNet internal definitions
 ********************************************************************/
#define		_DNET_REVISION				0x02

#define		_ATTRIB_REVISION			0x01

#define		_ATTRIB_MAC_ID				0x01
#define		_ATTRIB_BAUD_RATE			0x02
#define		_ATTRIB_BOI					0x03
#define		_ATTRIB_BO_COUNT			0x04
#define		_ATTRIB_ALLOC_INFO			0x05
#define		_ATTRIB_MAC_SW_CH			0x06
#define		_ATTRIB_BAUD_SW_CH			0x07
#define		_ATTRIB_MAC_SW_VAL			0x08
#define		_ATTRIB_BAUD_SW_VAL			0x09

#define		_DNET_ERR_CONFLICT			0x01
#define		_DNET_ERR_INVALID_PARAM		0x02
#define		_DNET_ERR_INVALID_SERVICE	0x03
#define		_DNET_ERR_RSRC_NOT_AVAIL	0x04


/*********************************************************************
 * DeviceNet global parameters
 ********************************************************************/
DNET uDNet;




/*********************************************************************
 * Function:        unsigned char DNetExplMsgHandler(void)
 *
 * PreCondition:    The path (aService, aClassID, aInstanceID) must
 *					be loaded prior to using this function. If service
 *					indicates any type of IO then the buffer pointers
 *					must be initialized.
 *
 * Input:       	aHeader, aClassID, aInstanceID, aService
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *					aOutBufLen, aInBufLen		
 *                  
 * Output:      	aHeader, aService	
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *				
 *			
 *
 * Side Effects:    
 *
 * Overview:        DeviceNet object explicit messaging handler. This
 *					fucntion is called by the Router object. It decodes
 *					the instance and service and performs the requested
 *					function.  
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetExplMsgHandler(void)
{
	switch (mRouteGetInstanceID())
	{
		// The DeviceNet object, class specific 
		case 0:
			switch(mRouteGetServiceID())
			{
				case SRVS_GET_ATTRIB_SINGLE:
					return (_DNetInst0GetAttrib());
				default:
					mRoutePutError(ERR_SERVICE_NOT_SUPPORTED);
					break;
			}
			break;
			
		// The DeviceNet object, instance 1 only
		case 1:
			switch(mRouteGetServiceID())
			{
				case SRVS_GET_ATTRIB_SINGLE:
					return (_DNetInst1GetAttrib());
				case SRVS_SET_ATTRIB_SINGLE:
					return (_DNetInst1SetAttrib());
				case SRVS_ALLOCATE_CONN:
					return (_DNetAllocateConnection());
				case SRVS_RELEASE_CONN:
					return (_DNetReleaseConnection());
				default:
					mRoutePutError(ERR_SERVICE_NOT_SUPPORTED);
					break;
			}
			break;
			
		// Handle all other invalid instances		
		default:	
			mRoutePutError(ERR_OBJECT_DOES_NOT_EXIST);			
			break;
	}
		
	return (1);
}			  



/*********************************************************************
 * Function:        unsigned char DNetInst0GetAttrib(void)
 *
 * PreCondition:    The path (aService, aClassID, aInstanceID) must
 *					be loaded prior to using this function. If service
 *					indicates any type of IO then the buffer pointers
 *					must be initialized.
 *
 * Input:       	aHeader, aClassID, aInstanceID, aService
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *					aOutBufLen, aInBufLen		
 *                  
 * Output:      	aHeader, aService	
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *				
 *			
 *
 * Side Effects:    
 *
 * Overview:        Get attribute service for instance 0.  
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetInst0GetAttrib(void)
{	
	switch (mRouteGetAttributeID())
	{
		case _ATTRIB_REVISION:
			mRoutePutByte(_DNET_REVISION & 0xFF);
			mRoutePutByte((_DNET_REVISION & 0xFF00) >> 8);
			break;
				
		default:
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED);
			break;
	}
  	return (1);
}



/*********************************************************************
 * Function:        unsigned char DNetInst1GetAttrib(void)
 *
 * PreCondition:    The path (aService, aClassID, aInstanceID) must
 *					be loaded prior to using this function. If service
 *					indicates any type of IO then the buffer pointers
 *					must be initialized.
 *
 * Input:       	aHeader, aClassID, aInstanceID, aService
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *					aOutBufLen, aInBufLen		
 *                  
 * Output:      	aHeader, aService	
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *				
 *			
 *
 * Side Effects:    
 *
 * Overview:        Get attribute service for instance 1.  
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetInst1GetAttrib(void)
{
	switch (mRouteGetAttributeID())
	{
		#if	ALLOW_MAC_ID
		case _ATTRIB_MAC_ID:
			mRoutePutByte(uDNet.MACID);
			break;
		#endif
	
		#if	ALLOW_BAUD_RATE
		case _ATTRIB_BAUD_RATE:
			mRoutePutByte(uDNet.BaudRate);
			break;
		#endif
				
		#if	ALLOW_BOI
		case _ATTRIB_BOI:
			mRoutePutByte(uDNet.BOI);
			break;
		#endif
				
		#if	ALLOW_BUS_OFF_COUNT
		case _ATTRIB_BO_COUNT:
			mRoutePutByte(uDNet.BusOffCount);
			break;
		#endif
				
		case _ATTRIB_ALLOC_INFO:
			mRoutePutByte(uDNet.AllocInfo.AllocChoice.byte);
			mRoutePutByte(uDNet.AllocInfo.MasterMACID);
			break;
									
		#if	ALLOW_MAC_ID_SW_CH
		case _ATTRIB_MAC_SW_CH:
			mRoutePutByte(uDNet.MACSwChange);
			break;
		#endif
				
		#if	ALLOW_BAUD_RATE_SW_CH
		case _ATTRIB_BAUD_SW_CH:
			mRoutePutByte(uDNet.BaudSwChange);
			break;
		#endif
				
		#if	ALLOW_MAC_ID_SW_VAL
		case _ATTRIB_MAC_SW_VAL:
			mRoutePutByte(uDNet.MACSwValue);
			break;
		#endif
				
		#if	ALLOW_BAUD_RATE_SW_VAL
		case _ATTRIB_BAUD_SW_VAL:
			mRoutePutByte(uDNet.BaudSwValue);
			break;
		#endif
				
		default:
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED);
			break;
	}
		
	return (1);
}




/*********************************************************************
 * Function:        unsigned char DNetInst1SetAttrib(void)
 *
 * PreCondition:    The path (aService, aClassID, aInstanceID) must
 *					be loaded prior to using this function. If service
 *					indicates any type of IO then the buffer pointers
 *					must be initialized.
 *
 * Input:       	aHeader, aClassID, aInstanceID, aService
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *					aOutBufLen, aInBufLen		
 *                  
 * Output:      	aHeader, aService	
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *				
 *			
 *
 * Side Effects:    
 *
 * Overview:        Set attribute service for instance 1.  
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetInst1SetAttrib(void)
{
	// Ignore the first byte (it is actually the attribute ID) 
	mRouteGetByte();

	switch (mRouteGetAttributeID())
	{
		#if ALLOW_MAC_ID && SETTABLE_MAC_ID
		case _ATTRIB_MAC_ID:
			if (mRouteTestValidInputDataLen(1))
			{
				// Perform system functions to be defined by the application
				UsrDNetSetAttribEvent();	
			}
			break;
		#endif
				
		#if ALLOW_BAUD_RATE && SETTABLE_BAUD_RATE
		case _ATTRIB_BAUD_RATE:
			if (mRouteTestValidInputDataLen(1))
			{
				// Perform system functions to be defined by the application
				UsrDNetSetAttribEvent();
			}
			break;
		#endif
			
		#if ALLOW_BOI && SETTABLE_BOI
		case _ATTRIB_BOI:
			if (mRouteTestValidInputDataLen(1))
			{
				// Perform system functions to be defined by the application
				UsrDNetSetAttribEvent();
			}
			break;
		#endif
				
		#if ALLOW_BUS_OFF_COUNT && SETTABLE_BUS_OFF_COUNT
		case _ATTRIB_BO_COUNT:
			if (mRouteTestValidInputDataLen(1))
			{
				uDNet.BusOffCount = 0;
			}
			break;
		#endif
		
				
		#if ALLOW_MAC_ID && !SETTABLE_MAC_ID
		case _ATTRIB_MAC_ID:
		#endif
		#if ALLOW_BAUD_RATE && !SETTABLE_BAUD_RATE
		case _ATTRIB_BAUD_RATE:
		#endif
		#if ALLOW_BOI && !SETTABLE_BOI
		case _ATTRIB_BOI:
		#endif
		#if ALLOW_BUS_OFF_COUNT && !SETTABLE_BUS_OFF_COUNT
		case _ATTRIB_BO_COUNT:
		#endif
		case _ATTRIB_ALLOC_INFO:
		#if ALLOW_MAC_ID_SW_CH
		case _ATTRIB_MAC_SW_CH:
		#endif
		#if ALLOW_BAUD_RATE_SW_CH
		case _ATTRIB_BAUD_SW_CH:
		#endif
		#if ALLOW_MAC_ID_SW_VAL
		case _ATTRIB_MAC_SW_VAL:
		#endif
		#if ALLOW_BAUD_RATE_SW_VAL
		case _ATTRIB_BAUD_SW_VAL:
		#endif
			mRoutePutError(ERR_ATTRIB_NOT_SETTABLE);
			break;
			
		default:
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED);
			break;
	}

	return (1);
}



/*********************************************************************
 * Function:        unsigned char DNetAllocateConnection(void)
 *
 * PreCondition:    The path (aService, aClassID, aInstanceID) must
 *					be loaded prior to using this function. If service
 *					indicates any type of IO then the buffer pointers
 *					must be initialized.
 *
 * Input:       	aHeader, aClassID, aInstanceID, aService
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *					aOutBufLen, aInBufLen		
 *                  
 * Output:      	aHeader, aService	
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen	
 *
 * Side Effects:    
 *
 * Overview:        Allocate predefined master/slave connection set.  
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetAllocateConnection(void)
{
	unsigned char allocMAC;
	BYTE allocChoice;

	// Pull the data from the buffer for validation
	allocChoice.byte = mRouteGetByte();
	allocMAC = mRouteGetByte();  
	 
	// Connection not allocated
	if (uDNet.AllocInfo.MasterMACID == 0xFF) 
	{
		// Since the device is not allocated then no connections 
		uDNet.AllocInfo.AllocChoice.byte = 0;

		// A NULL allocation choice is not valid
		if (allocChoice.byte == 0)
		{
			mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
			mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
		}

		// Check for connection support
		if (_DNetAllocNoSupportChk(allocChoice))
	   	{
	   		mRoutePutError(ERR_RESOURCE_UNAVAILABLE);
	   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
	   	}

		// Cannot allocate both COS and cyclic
	   	if ((allocChoice.byte & 0x30) == 0x30)
	   	{
	   		mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
	   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
	   	}

		// Cannot support acknowledge supression if COS or cyclic not enabled
		if ((allocChoice.byte & 0x70) == 0x40)
		{
	   		mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
	   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
		}
		
		// Cannot continue if a parent has not been allocated
		if (!allocChoice.bits.b0)
		{
			mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
			mRoutePutByte(_DNET_ERR_INVALID_PARAM);
			return (1);
		}
		
		// Set the master's MAC before attempting to create any 
		// connections because the Master's MAC is needed for the
		// bit-strobe connection upon creation.
		uDNet.AllocInfo.MasterMACID = allocMAC;
		
		// Try to create the connections
		if (!_DNetCreateConnections(allocChoice))
		{
	   		mRoutePutError(ERR_RESOURCE_UNAVAILABLE);
	   		mRoutePutByte(_DNET_ERR_RSRC_NOT_AVAIL);

			// Reset the Master's MAC
			uDNet.AllocInfo.MasterMACID = 0xFF;

			return (1);
		}
		
		uDNet.AllocInfo.AllocChoice.byte = allocChoice.byte;
	}

	// Connection is allocated
	else 
	{
		// Verify the request is from the allocated master
		if (uDNet.AllocInfo.MasterMACID != allocMAC)
		{
			mRoutePutError(ERR_OBJECT_STATE_CONFLICT);
			mRoutePutByte(_DNET_ERR_CONFLICT);

			return (1);
		}

		 // A NULL allocation choice is not valid
		if (allocChoice.byte == 0)
		{
			mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
			mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
		}

		// Check for connection support
		if (_DNetAllocNoSupportChk(allocChoice))
	   	{
	   		mRoutePutError(ERR_RESOURCE_UNAVAILABLE);
	   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
	   	}

		#if SUPPORT_COS && SUPPORT_CYCLIC
		// Cannot allocate both COS and cyclic
	   	if (((allocChoice.byte | uDNet.AllocInfo.AllocChoice.byte) & 0x30) == 0x30)
	   	{
	   		mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
	   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
	   	}
		#endif


		#if (SUPPORT_COS || SUPPORT_CYCLIC) && SUPPORT_POLLED
		// Cannot support polling if COS or cyclic is already enabled
		if ((uDNet.AllocInfo.AllocChoice.byte & 0x30) && (allocChoice.byte & 0x02))
		{
	   		mRoutePutError(ERR_RESOURCE_UNAVAILABLE);
	   		mRoutePutByte(_DNET_ERR_RSRC_NOT_AVAIL);

			return (1);
		}
		#endif

		// Cannot support acknowledge supression if COS or cyclic not enabled
		if (((allocChoice.byte | uDNet.AllocInfo.AllocChoice.byte) & 0x70) == 0x40)
		{
	   		mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
	   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

			return (1);
		}
		
		// Cannot continue if the request matches existing connections
		if ((allocChoice.byte & uDNet.AllocInfo.AllocChoice.byte) & 0x3F)
		{
			mRoutePutError(ERR_OBJECT_STATE_CONFLICT);
			mRoutePutByte(_DNET_ERR_CONFLICT);

			return (1);
		}

		// Try to create the connections
		if (!_DNetCreateConnections(allocChoice))
		{
	   		mRoutePutError(ERR_RESOURCE_UNAVAILABLE);
	   		mRoutePutByte(_DNET_ERR_RSRC_NOT_AVAIL);

			return (1);
		}
		
		// Set the alloc choice
		uDNet.AllocInfo.AllocChoice.byte |= allocChoice.byte;
	}
	
	// Set the responce format   (Message Body Format)
	#if ((!CLASS_WIDTH_16BIT) && (!INSTANCE_WIDTH_16BIT))
	mRoutePutByte(0);
	#endif
	#if ((!CLASS_WIDTH_16BIT) && INSTANCE_WIDTH_16BIT)
	mRoutePutByte(1);
	#endif
	#if (CLASS_WIDTH_16BIT && INSTANCE_WIDTH_16BIT)
	mRoutePutByte(2);
	#endif
	#if (CLASS_WIDTH_16BIT && (!INSTANCE_WIDTH_16BIT))
	mRoutePutByte(3);
	#endif
	
	return (1);
}



/*********************************************************************
 * Function:        unsigned char DNetReleaseConnection(void)
 *
 * PreCondition:    The path (aService, aClassID, aInstanceID) must
 *					be loaded prior to using this function. If service
 *					indicates any type of IO then the buffer pointers
 *					must be initialized.
 *
 * Input:       	aHeader, aClassID, aInstanceID, aService
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *					aOutBufLen, aInBufLen		
 *                  
 * Output:      	aHeader, aService	
 *					*pOutBuf, *pInBuf, aOutBufDataLen, aInBufDataLen
 *				
 * Side Effects:    
 *
 * Overview:        Release predefined master/slave connection set.  
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetReleaseConnection(void)
{
	BYTE releaseChoice;

	releaseChoice.byte = mRouteGetByte();
	
	// Check for connection support
	if (_DNetAllocNoSupportChk(releaseChoice))
   	{
   		mRoutePutError(ERR_RESOURCE_UNAVAILABLE);
   		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

   		return (1);
   	}

	 // A NULL release choice is not valid
  	if (releaseChoice.byte == 0)
  	{
  		mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
  		mRoutePutByte(_DNET_ERR_INVALID_PARAM);

  		return (1);
  	}
	
   	// Cannot continue if the request matches non-existant connections
   	if (((releaseChoice.byte) & (~uDNet.AllocInfo.AllocChoice.byte)) & 0x3F)
   	{
   		mRoutePutError(ERR_OBJECT_STATE_CONFLICT);
   		mRoutePutByte(_DNET_ERR_CONFLICT);

   		return (1);
   	}
	
	// Close the connections
	_DNetCloseConnections(releaseChoice);
	
	// Release the connection(s)
	uDNet.AllocInfo.AllocChoice.byte &= (~(releaseChoice.byte));	 
	
	// If all connections are released then reset the master MAC ID
	if (uDNet.AllocInfo.AllocChoice.byte == 0) uDNet.AllocInfo.MasterMACID = 0xFF; 													 
	
	// If ack supression is set and cyclic/COS is not then clear the bit
	if ((uDNet.AllocInfo.AllocChoice.byte & 0x70) == 0x40) uDNet.AllocInfo.AllocChoice.byte &= 0x0F;
														 
	return (1);											 
}



/*********************************************************************
 * Function:        unsigned char _DNetAllocNoSupportChk(BYTE choice)
 *
 * PreCondition:    None
 *
 * Input:       	The allocation choice as a bitmap	
 *                  
 * Output:      	1 or 0
 *				
 * Side Effects:    None
 *
 * Overview:       	Validates the allocation choice to determine if a
 *					connection is not supported. Returns TRUE if the
 *					any of the connections are not supported.
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetAllocNoSupportChk(BYTE choice)
{	
	#if SUPPORT_POLLED == 0
	if (choice.bits.b1) return (1);		// Polled messgae not supported
	#endif

	#if SUPPORT_BIT_STROBED == 0
	if (choice.bits.b2) return (1);		// Bit Strobed not supported
	#endif

	#if SUPPORT_MULTICAST_POLL == 0
	if (choice.bits.b3) return (1);		// Multicast Polled Message not supported
	#endif

	#if SUPPORT_COS == 0
	if (choice.bits.b4) return (1);		// COS Message not supported
	#endif
	 
	#if SUPPORT_CYCLIC == 0
	if (choice.bits.b5) return (1);		// Cyclic Message not supported
	#endif	

	if (choice.bits.b7) return (1);		// Reserved bit	never supported							   
	
	return (0);
} 



/*********************************************************************
 * Function:        void _DNetCreateConnections(BYTE choice)
 *
 * PreCondition:    None
 *
 * Input:       	The allocation choice as a bitmap
 *                  
 * Output:      	None
 *				
 * Side Effects:    This function will call to individual connection
 *					objects to open. If any open request fails then 
 *					any objects that were just opened will be closed 
 *					immediately.
 *
 * Overview:      	This function decodes the request and calls
 *					the appropriate functions to create the connection.
 *
 * Note:            None
 ********************************************************************/
unsigned char _DNetCreateConnections(BYTE choice)
{
	BYTE allocProgress;
	unsigned char err_stat;

	err_stat = 1;
	allocProgress.byte = 0;

	// Allocate Explicit Messaging if not already allocated
	if (choice.bits.b0) 					// Explicit message
	{
		if (_Conn1Create()) allocProgress.bits.b0 = 1;
		else err_stat = 0;
	}
		
	#if SUPPORT_POLLED
	if (choice.bits.b1) 					// Polled message
	{
		if (_Conn2Create()) allocProgress.bits.b1 = 1;
		else err_stat = 0;
	}
	#endif		
		
	#if SUPPORT_BIT_STROBED
	if (choice.bits.b2) 					// Bit Strobed Message
	{
		if (_Conn3Create()) allocProgress.bits.b2 = 1;
		else err_stat = 0;
	}
	#endif	
	
	#if SUPPORT_MULTICAST_POLL
	if (choice.bits.b3) 					// Multicast Polled Message
	{
		if (_Conn5Create()) allocProgress.bits.b4 = 1;
		else err_stat = 0;
	}
	#endif		
		
	#if SUPPORT_COS
	if (choice.bits.b4) 					// COS Message
	{
		if (_Conn4Create()) 
		{
			allocProgress.bits.b3 = 1;
			
			#if SUPPORT_COS_BOTH_DIR		
			#if SUPPORT_POLLED
			if (!uDNet.AllocInfo.AllocChoice.bits.poll)
			{
				if (_Conn2Create()) allocProgress.bits.b1 = 1;
				else err_stat = 0; 
			}
			#else
			if (_Conn2Create()) allocProgress.bits.b1 = 1;
			else err_stat = 0; 
			#endif
			#endif
		}
		else err_stat = 0;
	}
	#endif	
		
	#if SUPPORT_CYCLIC
	if (choice.bits.b5) 					// Cyclic Message
	{
		if (_Conn4Create()) 
		{
			allocProgress.bits.b3 = 1;
			
			#if SUPPORT_COS_BOTH_DIR		
			#if SUPPORT_POLLED
			if (!uDNet.AllocInfo.AllocChoice.bits.poll)
			{
				if (_Conn2Create()) allocProgress.bits.b1 = 1;
				else err_stat = 0; 
			}
			#else
			if (_Conn2Create()) allocProgress.bits.b1 = 1;
			else err_stat = 0; 
			#endif
			#endif
		}
		else err_stat = 0;
	}
	#endif
	
	// Close all just opened connections if there was an error
	if (err_stat == 0)
	{
		if (allocProgress.bits.b0) _Conn1Close();
		
		#if SUPPORT_POLLED || SUPPORT_COS_BOTH_DIR
		if (allocProgress.bits.b1) _Conn2Close();
		#endif
		
		#if SUPPORT_BIT_STROBED
		if (allocProgress.bits.b2) _Conn3Close();
		#endif
		
		#if SUPPORT_COS || SUPPORT_CYCLIC
		if (allocProgress.bits.b3) _Conn4Close();
		#endif
		
		#if SUPPORT_MULTICAST_POLL
		if (allocProgress.bits.b4) _Conn5Close();
		#endif
	}
			
	return (err_stat);
}




/*********************************************************************
 * Function:        void _DNetCreateConnections(BYTE choice)
 *
 * PreCondition:    
 *
 * Input:       			
 *                  
 * Output:      	
 *				
 * Side Effects:    
 *
 * Overview:     	This function decodes the choice byte and calls
 *					the appropriate functions to delete the connections.     
 *
 * Note:            None
 ********************************************************************/
void _DNetCloseConnections(BYTE choice)
{	
	if (choice.bits.b0) _Conn1Close();		// Explicit message 

	#if SUPPORT_POLLED
	if (choice.bits.b1) _Conn2Close();		// Polled messgae
	#endif

	#if SUPPORT_BIT_STROBED
	if (choice.bits.b2) _Conn3Close();		// Bit Strobed
	#endif

	#if SUPPORT_MULTICAST_POLL
	if (choice.bits.b3) _Conn5Close();		// Multicast Polled Message
	#endif

	#if SUPPORT_COS
	if (choice.bits.b4) 					// COS Message
	{
		_Conn4Close();
		
		#if SUPPORT_COS_BOTH_DIR		
		#if SUPPORT_POLLED
		if (!uDNet.AllocInfo.AllocChoice.bits.poll)
		{
			_Conn2Close(); 
		}
		#else
		_Conn2Close();
		#endif
		#endif
		
				
		#if SUPPORT_POLLED
		if (!uDNet.AllocInfo.AllocChoice.bits.poll) 
		#endif
			#if SUPPORT_COS_BOTH_DIR
			_Conn2Close();
			#endif
	}
	#endif
	 
	#if SUPPORT_CYCLIC
	if (choice.bits.b5) 					// Cyclic Message
	{
		_Conn4Close();		
		#if SUPPORT_POLLED
		if (!uDNet.AllocInfo.AllocChoice.bits.poll) 
		#endif
			#if SUPPORT_COS_BOTH_DIR
			_Conn2Close();
			#endif
	}
	#endif
}


