/*-------------------------------------------------------------------
	ModbusProtocol.h
	-------------------------------------------------------------------

	(c) Vector Informatik GmbH. All rights reserved.

	------------------------------------------------------------------- */ 

#pragma once

#include <fstream>

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

/*--------------------------------------------------------------------*/
//! Signal protocol class
/*! 
		This class implements the NIPB::IProtocol interface. It handles the
	Modbus protocol

		The protocol is located within a UDP protocol and uses the UDP
		ports 50002 and 502. The first 8 Bytes of the UDP payload
		contain the header:
		[0,2] Transaction ID	
		[2,2] Protocol ID		(Modbus := 0x0000)
		[4,2] Length			(Number of following bytes)
		[6,1] Unit ID			(not used)
		[7,1] Function Code
*/
class ModbusProtocol : 
	public NIPB::IProtocol
{
private:
	static const ULONG kHeaderLength    = 8;				// see above
	static const ULONG kHeaderBitLength = kHeaderLength*8;
public:
	static const WORD kClientPort		= 502;
	static const WORD kServerPort		= 502;

	//
	// Construction
	//
public:
	ModbusProtocol();

	//
	// IProtocol
	//
public:
	//! Initialize the protocol
	/*!
		\param protocolManager The protocol manager for this protocol. The pointer can be stored and is valid
					                during the whole lifetime of the IProtocol object.
		\param networkModel    The network model for this protocol. The pointer can be stored and is valid
					                during the whole lifetime of the IProtocol object.
		\param modelCreator    Define network model entities with this object. Pointer is only valid during this call.
	*/
	VDEF Initialize      ( NIPB::IProtocolManager /*in*/ *protocolManager, NIPB::INetworkModel /*in*/ *networkModel, NIPB::INetworkModelCreator /*in*/ *modelCreator );
	//! Deinitialize the protocol
	/*!
		\param protocolManager The protocol manager for this protocol. The pointer is invalid after Deinitialize.
		\param networkModel    The network model for this protocol. The pointer is invalid after Deinitialize.
	*/
	VDEF Deinitialize    ( NIPB::IProtocolManager /*in*/ *protocolManager, NIPB::INetworkModel /*in*/ *networkModel );
	//! Returns the textual designator of the protocol
	/*!
			The designator is used to access the protocol in CAPL (via Nodelayer) or the GUI of CANoe/CANalyzer.

			\param bufferSize   Length of 'buffer'. Must not > 0
			\param buffer       The designator is copied to this buffer. Must not be 0
	*/
	VDEF GetDesignator   ( unsigned long /*in*/ bufferSize, char /*out**/ *buffer );
	//! Unique token identifier of the protocol
	/*!
			The VTokenId of the protocol is registerd on startup during defintion of the protocol token.

			\param identifier  A pointer to a VTokenId, which retrieves the identifier. Must not be 0
	*/
	VDEF GetIdentifier   ( NIPB::VTokenId /*out*/ *identifier );
	//! Returns specific encoder for a token ID
	/*!
			The IEncoder is used to access a token within a IPacket.

			\param tokenId  Token identifier for which the encoder is requested.
			\param encoder  Returns a pointer to the encoder. Must not be 0.
	*/
	VDEF GetEncoder      ( NIPB::VTokenId /*in*/ tokenId, NIPB::IEncoder /*out*/ **encoder );
	//! Initialize a specific protocol during creation of a new packet
	/*!
			Use this method to setup a protocol within a packet.

			\param packet           The packet where the protocol should be setup. Must not be 0.
			\param protocolTypeId   Type ID for a specific type of the protocol, i.e ARP request or ARP response
			\param topProtocolToken Points to the top most protocol within the packet.
			\param protocolToken    This strucuture must be filled in InitProtocol.
	*/
	VDEF InitProtocol    ( NIPB::IPacket /*in*/ *packet, NIPB::VTokenId /*in*/ protocolTypeId, const NIPB::VProtocolToken /*in*/ *topProtocolToken, NIPB::VProtocolToken /*out*/ *protocolToken);	
	//! Complete the protocol at the end of creation/modification of a packet.
	/*!
		In this function the checksum or length field of a protocol can be calculated.

		\param packet   The packet to complete
		\param protocol Points to the protocol token for this protocol
	*/
	VDEF CompleteProtocol( NIPB::IPacket /*in*/ *packet, const NIPB::VProtocolToken /*in*/ *modbus );	// Is *modbus UDP or Modbus?

	//! Parse a received packet.
	/*!
			The method is called, when a packet is parsed. During parsing the VProtocols structure is initialzed
			with the protocol information, whiche are returnd with 'protocolToken'.

			\param packet            The packet to parse.
			\param topProtocolToken  Points to the top most, already parsed protocol within the packet.
			\param errorWriter       Use this interface to returne parsing errors, i.e wrong checksum
			\param nextProcotolId    Return the VTokenId of the next protocol.
			\param protocolToken     Fill this strucutre to setup the VProtocols structure.
	*/
	VDEF ParsePacket     ( NIPB::IPacket /*in*/ *packet, const NIPB::VProtocolToken /*in*/ *topProtocolToken, NIPB::IFormatter /*in*/ *errorWriter, NIPB::VTokenId /*out*/ *nextProcotolId, NIPB::VProtocolToken /*out*/ *protocolToken );
	//! Return a token of a protocol.
	/*!
		The function must fill the 'token' with the information of the request 'tokenId'.

		\param protocolToken  Points the the VProtocolToken for the protocol.
		\param tokenId        The identifier of the requested token.
		\param token          Points to a VToken, which must be fille by this function.
	*/
	VDEF GetToken        ( const NIPB::VProtocolToken /*in*/ *protocolToken, NIPB::VTokenId /*in*/ tokenId, NIPB::VToken /*out*/ *token );
	//! Build a tree with information of the protocol.
	/*!
			The function is used in CANoe/CANalyzer in the detail view of the trace window to build
			a tree with protocols and fields.

			\param protocolToken  Protocol token of this protocol
			\param type           Inspection type
			\param inspector      IPacketInspectore to create the output.
	*/
	VDEF InspectProtocol ( const NIPB::VProtocolToken /*in*/ *protocolToken, NIPB::VInspectionType /*in*/ type, NIPB::IPacketInspector /*in*/ *inspector );

	//
	// Methods
	//
public:
	ULONG GetContentId(		const BYTE *packetData, ULONG packetLength, const NIPB::VProtocolToken &protocol );
	WORD GetTxId(			const BYTE *packetData, ULONG packetLength, const NIPB::VProtocolToken &protocol );
	ULONG GetIp(			const BYTE *packetData, ULONG packetLength, const NIPB::VProtocolToken &protocol );
	BYTE GetFuncCode(		const BYTE *packetData, ULONG packetLength, const NIPB::VProtocolToken &protocol );
	BYTE GetFirstDataByte(	const BYTE *packetData, ULONG packetLength, const NIPB::VProtocolToken &protocol );
	ULONG GetAddrNCount(	const BYTE *packetData, ULONG packetLength, const NIPB::VProtocolToken &protocol );

	static NIPB::VResult MakeHeaderToken( const NIPB::VProtocolToken /*in*/ *protocolToken, NIPB::VTokenId /*in*/ tokenId, ULONG /*in*/ offset, ULONG /*in*/ length, NIPB::VToken /*out*/ *token );
	static NIPB::VResult MakePayloadToken( const NIPB::VProtocolToken /*in*/ *protocolToken, NIPB::VTokenId /*in*/ tokenId, ULONG /*in*/ offset, ULONG /*in*/ length, NIPB::VToken /*out*/ *token );
	static void FormatUnsigned( NIPB::IPacketInspector *inspector, LPCTSTR label, NIPB::VTokenId tokenId, ULONG value, ULONG valueLength );
	static void FormatUnsigned( NIPB::IPacketInspector *inspector, LPCTSTR labelPre, NIPB::VTokenId tokenId, LPCTSTR labelPost, ULONG value, ULONG valueLength );
	static void FormatString( NIPB::IPacketInspector *inspector, LPCTSTR text );

	static NIPB::VResult SetTokenUnsigned( NIPB::VProtocolToken &protocolToken, NIPB::VTokenId tokenId, ULONG valueLength, ULONG value );
	static NIPB::VResult SetTokenData( NIPB::VProtocolToken &protocolToken, NIPB::VTokenId tokenId, ULONG dataLength, const BYTE *data );

	//
	// Attributes
	//
private:
	NIPB::VTokenId          mProtocolId;	//!< Token ID of this protocol

	NIPB::VTokenId          mTxId;			//!< Token ID of the 'TxID' field
	NIPB::VTokenId          mProtType;		//!< Token ID of the 'ProtocolID' field
	NIPB::VTokenId          mLength;		//!< Token ID of the 'Length' field
	NIPB::VTokenId          mUnitId;		//!< Token ID of the 'UnitID' field
	NIPB::VTokenId          mFuncCode;		//!< Token ID of the 'FuncCode' field

	NIPB::IProtocolManager *mProtocolManager;

	std::ofstream			log;
};

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
