Modified for W5500 Ethernet initialize Added the Ethernet interface re-initialize code Added the connection retry

Dependents:   ThingPlug_Ethernet_Example

Fork of GMMP_mbed by Eric Jung

GMMP.h

Committer:
lesmin
Date:
2015-08-09
Revision:
0:7e575e5f88ec

File content as of revision 0:7e575e5f88ec:

/**
 * @mainpage GMMP (Global M2M Protocol) 개요
  * @brief GMMP는 M2M 단말과 개방형 M2M 플랫폼(OMP)사이의 TCP 기반 연동 규격으로서, 단말 등록/해지, 주기보고, 단말 제어 등의 기능을 수행하는 SKTelecom 내부 규격이다.
 * @brief M2M Portal Site : <a href="https://www.m2mportal.co.kr"> Mobius Portal </a>
 * @date 2015/07/20
 * @version 1.0
 * @file GMMP.h
 **/


#ifndef GMMP_H_
#define GMMP_H_

#include "GMMP_Operation.h"

/**
 * @defgroup GMMP_Registration_Operation M2M GW/Device 등록
 *등록 절차는 현장에 설치된 M2M GW가 서비스 수행을 시작하기 위해서 최초로 수행해야 하는 절차이다.\n
 *1. GW 등록 절차\n
(1) M2M GW는 M2M Portal을 통해 사전에 등록된 자기 자신의 AUTH_ID(MSISDN or MAC Address), Domain Code, Manufacture ID를 전송한다.\n
(2) OMP는 M2M GW가 전송한 AUTH_ID(MSISDN or MAC Address), Manufacture ID 값이 정상인지 확인하고 이상이 없으면 M2M GW로 Auth Key, GW ID를 부여하여 응답 메시지를 전송한다.\n
(3) OMP에서 M2M GW의 등록이 정상적으로 이루어지지 않으면 응답 메시지의 Result Code에 Fail Code 값을 포함하여 M2M GW로 전송한다.\n
(4) 3회 이상 M2M GW의 등록이 정상적이지 않은 경우 M2M GW는 더 이상 등록 요청을 수행하지 않고 GW 장애 절차를 수행한다.(GMMP 규격 논외)\n
(5) M2M GW의 등록이 정상적으로 수행되었으나 Profile 정보(주기보고의 주기정보 및 Heartbeat 주기정보 등)가 없는 경우에는 @ref GO_Profile을 수행한다.\n

	NOTE :\n
	[사전 등록] M2M GW 등록 절차 수행을 위해서는 사전에 M2M 포털을 통해 등록 되어야 한다.\n
	[ID 등록] M2M GW의 Auth ID(MSISDN, MAC) 또는 Manufacture ID가 변경되었으나 M2M 포털을 통해 갱신 등록되지 않으면 M2M 단말 등록 절차는 Fail 처리 된다.\n
	[정상 등록] 등록 요청이 정상적으로 수행된 경우 더 이상 등록 절차를 수행 하지 않는다.\n
	[재 등록 요청] OMP 에 등록 과정을 수행한 단말에 대해서 전원을 껐다(Off) 켜(On)는 경우에는 재 등록을 수행할 필요가 없다. 단, 할당 받은 GW ID, Auth Key, Domain Code 등의 값이 유실되거나 삭제된 경우에는 재 등록 요청을 수행 할 수 있다.\n
	[할당 Field 사용] Auth Key 값은 GMMP Common Header의 Auth_key 필드에 설정되며, Domain Code, GW ID 값은 Message Type별 Field 정의영역 부분에 설정되어 반환 된다. 이후 모든 메시지에는 반드시 OMP에서 할당된 Auth Key, GW ID 값을 해당 메시지에 이용되어야 한다.\n
	[중복 등록 허용] 이미 등록되어 있는 M2M GW에 대해 재 등록 요청을 하는 경우에는 중복 등록이 허용이 된다. 이때 전달되는 Auth Key, GW ID 값은 이전의 등록절차에서 할당 되었던 동일한 값이 전달된다.\n
	[M2M GW Timeout] M2M GW에서 OMP로 Request 명령을 전송한 뒤 응답이 없는 경우 Timeout 처리를 수행한다. 이 값은 Profile 정보에 포함 되어 있으며, OMP의 제어 명령에 의해서 변경 될 수 있다. (Timeout은 default로 최소 30sec 이상으로 설정되어야 한다)\n

전송 패킷 : @ref Struct_Reg_GW.h, @ref Struct_Reg_Device.h 참조

 * @ingroup GMMP_Registration_Operation
 * @{
 */

/**
 *
 *@brief GW,Device 등록 절차 진행 명령 함수, 옵션으로 암호화 진행 유무 Flag가 있다.\n
 등록 절차는 현장에 설치된 M2M GW가 서비스 수행을 시작하기 위해서 최초로 수행해야 하는 절차이다.\n
 등록 절차를 통해 GW ID, Device ID를 OMP로 부터 제공 받는다.\n
 *@warning GW 등록 절차가 진행되어야만 Device 등록 절차를 진행 할 수 있다.\n
 * @param pszGWID OMP에서 제공받은 GW ID, NULL이면 GW 등록, 아니면 Device 등록 절차를 진행한다.\n
 * @param pszManufactureID M2M GW,Device의 Manufacture ID이다.\n
- AlphaNumeric : 문자,숫자 조합, 특수문자제외, SPACE 허용 안하며 빈자리는 0x00(NULL)로 채운다.\n
Ex) 공장 제조 Serial No. : “AVB12132SET23DT”, “SKTSerial“\n
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 *
 * @code GW/Device 등록 샘플 코드 (Sample_Registration 샘플 참조)

int GW_Reg()
{
	int nRet = GMMP_SUCCESS;

	nRet = GO_Reg(NULL, pszGWMFID, false);

	if(nRet < 0)
	{
		printf("GW GO_Reg Error : %d\n", nRet);

		return 1;
	}

	return 0;
}

int Device_Reg()
{
	int nRet = GMMP_SUCCESS;

	nRet = GO_Reg(GetGWID(), pszDeviceMFID, false);

	if(nRet < 0)
	{
		printf("GW GO_Reg Error : %d\n", nRet);

		return 1;
	}

	return 0;
}

int Init()
{
	if(Initialize(szServerIP, nServerPort, pszDomainCode , pszGWAuthID, GMMP_ON_LOG, nErrorLevel, GMMP_NETWORK_ALYWAYS_OFF, "Log") != 0)
	{
		printf("Server Connect Error\n");

		return 1;
	}

	SetCallFunction( (void*)Recv);

	return 0;
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	if(GW_Reg() != 0)
	{
		printf("GW_Reg Error");
		return -1;
	}

	if(Device_Reg() != 0)
	{
		printf("Device_Reg Error");
		return -1;
	}

	return 0;

}
 @endcode
 */

int GO_Reg(const char* pszGWID,
const char* pszManufactureID);
/**
 * @}
 */

/**
 * @defgroup GMMP_DeRegistration_Operation M2M GW/Device 등록 해지
 *해지 절차는 M2M Device가 더 이상 서비스를 수행하지 않음을 OMP에 알리는 절차로서 Device ID값이 OMP에 반납된다.\n
 * GMMP_Device_DeRegistration_Request 메시지를 이용하여 해지 요청을 수행하고, \n
 * GMMP_Device_DeRegistration_Response 메시지를 통해 해지 결과를 받는다.\n
 * 현장에서 문제가 생기거나 또는 철거하는 경우 M2M 포털을 통해서 해지(DeRegistration)할 수 있다.\n
 * 이때 M2M GW가 DeRegistration 하는 경우 하위 Device 정보도 모두 해제 된다.

전송 패킷 : @ref Struct_DeReg_GW.h, @ref Struct_DeReg_Device.h 참조

 * @ingroup GMMP_DeRegistration_Operation
 * @{
 */

/**
 *@brief GW,Device 해지 절차 진행 명령 함수
 *@brief 해지 절차는 등록 절차를 통해 OMP로 부터 제공 받은 GW ID, Device ID를 해지 한다.
 *@warning GW 등록 절차가 진행되어야만 Device 등록 절차를 진행 할 수 있다. GW 등록 해제 절차를 진행할 경우 하위 Device에 대해 자동 해지가 된다.
 *@warning OMP 연동을 통해 서비스를 재개하기 위해서는 다시 OMP를 통해 Auth Key, GW ID를 할당 받아야 한다.
 * @param pszGWID OMP로 제공 받은 GW ID값.
 * @param pszDeviceID OMP로 제공 받은 Device ID값.
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 *
 * @code GW/Device 등록 해지 샘플 코드 (Sample_DeRegistration 샘플 참조)  샘플코드 참조
 *
int GW_DeReg()
{
	int nRet = GMMP_SUCCESS;

	nRet = GO_DeReg(pszGWID, NULL);

	if(nRet < 0)
	{
		printf("GW GO_Reg Error : %d\n", nRet);

		return 1;
	}

	return 0;
}

int Device_DeReg()
{
	int nRet = GMMP_SUCCESS;

	nRet = GO_DeReg(GetGWID(), pszDeviceID);

	if(nRet < 0)
	{
		printf("GW GO_Reg Error : %d\n", nRet);

		return 1;
	}

	return 0;
}

int Init()
{
	if(Initialize(szServerIP, nServerPort, pszDomainCode , pszGWAuthID, GMMP_ON_LOG, nErrorLevel, GMMP_NETWORK_ALYWAYS_OFF, "Log") != 0)
	{
		printf("Server Connect Error\n");

		return 1;
	}

	SetCallFunction( (void*)Recv);
	SetAuthKey(pszAuthKey);
	SetGWID(pszGWID);

	return 0;
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	if(GW_DeReg() != 0)
	{
		printf("GW_Reg Error");
		return -1;
	}

	if(Device_DeReg() != 0)
	{
		printf("Device_Reg Error");
		return -1;
	}

	return 0;

}
 @endcode
 */
int GO_DeReg(const char* pszGWID,
		const char* pszDeviceID);

/**
 * @}
 */

/**
 * @defgroup GMMP_ProfileInfo_Operation M2M GW/Device Profile Info
 *
M2M GW에 Profile 정보가 없는 경우에 또는 일부 존재 하지 않는 경우 OMP에 Profile 정보를 요청한다.\n
Profile 정보가 미리 설정되어 있는 경우에는 Profile 요청 절차를 수행하지 않는다.\n
M2M GW의 등록 절차 또는 M2M Device 등록 절차 이후에 수행될 수 있다. \n
또한 OMP로부터 제어 명령(@ref GMMP_Control_Operation, Control Type @ref CONTROL_Profile_Reset)을 수신한 경우 Profile 정보 Operation을 수행한다.

전송 패킷 : @ref Struct_ProfileInfo.h 참조

 * @ingroup GMMP_ProfileInfo_Operation
 * @{
 */
/**
 * @param pszGWID OMP로 제공 받은 GW ID값.
 * @param pszDeviceID OMP로 제공 받은 Device ID값.
 * @param nTID T-ID는 M2M GW와 OMP 간의 트랜잭션을 구분하기 위한 값으로서 Request 요청하는 곳에서 할당하며 Response 받은 곳에서는 해당 T-ID 값을 그대로 반환한다.\n
				M2M GW와 OMP에서 T-ID 사용 범위는 다음과 같다.\n
				※ M2M GW T-ID : 0 ~ 99,999 (10만개)\n
				※ OMP T-ID : M2M GW가 사용 이외의 값\n
 *
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 * @code GW/Device Profile Info 요청 샘플 코드 (Sample_Profile 샘플 참조)

int GW_Profile()
{
	int nRet = GMMP_SUCCESS;

	nRet = GO_Profile(pszGWID, NULL, nTID);

	if(nRet < 0)
	{
		printf("GW GO_Profile Error : %d\n", nRet);

		return 1;
	}

	return 0;
}

int Device_Profile()
{
	int nRet = GMMP_SUCCESS;

	nRet = GO_Profile(pszGWID, pszDeviceID, nTID);

	if(nRet < 0)
	{
		printf("GW GO_Profile Error : %d\n", nRet);

		return 1;
	}

	return 0;
}

int Init()
{
	if(Initialize(szServerIP, nServerPort, pszDomainCode , pszGWAuthID, GMMP_ON_LOG, nErrorLevel, GMMP_NETWORK_ALYWAYS_OFF, "Log") != 0)
	{
		printf("Server Connect Error\n");

		return 1;
	}

	SetCallFunction( (void*)Recv);
	SetAuthKey(pszAuthKey);

	return 0;
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	if(GW_Profile() != 0)
	{
		printf("GW_Profile Error");
		return -1;
	}

	if(Device_Profile() != 0)
	{
		printf("Device_Profile Error");
		return -1;
	}

	return 0;

}
 @endcode
 */
int GO_Profile(const char* pszGWID,
		const char* pszDeviceID,
		const long nTID);
/**
 * @}
 */

/**
 * @defgroup GMMP_Delivery_Operation M2M GW/Device 주기 보고
 *
M2M 단말에서 수집된 데이터를 OMP로 전송하는 절차이다.\n
수집된 데이터를 전송하는 M2M 단말은 반드시 등록 절차를 통해 OMP에 등록되어 있어야 한다.\n
수집된 데이터는 타입에 따라서 수집 데이터(collect data), 장애 데이터(alarm data), 이벤트 데이터(event data), 장애 해제(alarm clear) 데이터 등으로 분류 된다.\n
이 값에 대한 설정은 cReportType 변수의 Report Type에 따라 구분된다. @ref Define_Delivery.h 참조

전송 패킷 : @ref Struct_Delivery.h 참조

 * @ingroup GMMP_Delivery_Operation
 * @{
 */
/**
 *
 * @param pszGWID OMP로 제공 받은 GW ID값.
 * @param pszDeviceID OMP로 제공 받은 Device ID값.
 * @param cReportType Report Type\n @ref Define_Delivery.h 참조
 - 0x01 : collect data\n
 - 0x02 : alarm data\n
 - 0x03 : event data\n
 - 0x04 : alarm clear\n
 *
 * @param cMediaType Message Body의 미디어 타입을 의미 @ref Struct_Delivery.h 참조
 * @param pszMessageBody Data[2048 Byte]
 * @param nTotalCount Message Body에 전달될 내용이 2048 Bytes를 초과할 경우 여러 개의 메시지로 전송하며 전체 메시지 개수를 표시 한다
 * @param nCurrentCount 여러 개의 메시지로 전송되는 경우 현재 메시지의 순서로서 1에서 Total Count까지의 값이 기록 된다.
  * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조

 @code GW/Device 주기 보고 샘플 코드 (Sample_Delivery 샘플 참조)
int GW_Delivery()
{
	int nRet = 0;
	int nTotalCount = 0;
	int nLoop = 0;
	int nMessageBodyLen = strlen(pszMessage);

	if(nMessageBodyLen < MAX_MSG_BODY)
	{
		nTotalCount = 1;
	}
	else
	{
		nTotalCount = nMessageBodyLen/MAX_MSG_BODY;

		if(nMessageBodyLen%MAX_MSG_BODY > 0)
		{
			nTotalCount++;
		}
	}

	int nMessagePos = 0;
	int nSendLen = 0;
	int nSendedLen = nMessageBodyLen;

	char szMessage[MAX_MSG_BODY];

	for(nLoop = 1 ; nLoop <= nTotalCount ; nLoop++)
	{
		memset(szMessage, 0, sizeof(szMessage) );

		if(nSendedLen >= MAX_MSG_BODY)
		{
			nSendLen = MAX_MSG_BODY;
		}
		else
		{
			nSendLen = nSendedLen;
		}

		memcpy(szMessage, pszMessage+nMessagePos, nSendLen);

		printf("Send Message Len = %d\n", strlen(szMessage) );

		nRet = GO_Delivery(pszGWID, NULL, DELIVERY_COLLECT_DATA,  0x01, szMessage);

		if(nRet < 0)
		{
			printf("GO_Delivery Error : %d\n", nRet);

			return 1;
		}

		nSendedLen -= nSendLen;
		nMessagePos+= nSendedLen;
	}

	return 0;
}

int Device_Delivery()
{
	int nRet = 0;
	int nTotalCount = 0;
	int nLoop = 0;
	int nMessageBodyLen = strlen(pszMessage);

	if(nMessageBodyLen < MAX_MSG_BODY)
	{
		nTotalCount = 1;
	}
	else
	{
		nTotalCount = nMessageBodyLen/MAX_MSG_BODY;

		if(nMessageBodyLen%MAX_MSG_BODY > 0)
		{
			nTotalCount++;
		}
	}

	int nMessagePos = 0;
	int nSendLen = 0;
	int nSendedLen = nMessageBodyLen;

	char szMessage[MAX_MSG_BODY];

	for(nLoop = 1 ; nLoop <= nTotalCount ; nLoop++)
	{
		memset(szMessage, 0, sizeof(szMessage) );

		if(nSendedLen >= MAX_MSG_BODY)
		{
			nSendLen = MAX_MSG_BODY;
		}
		else
		{
			nSendLen = nSendedLen;
		}

		memcpy(szMessage, pszMessage+nMessagePos, nSendLen);

		printf("Send Message Len = %d\n", strlen(szMessage) );

		nRet = GO_Delivery(pszGWID, pszDeviceID, DELIVERY_COLLECT_DATA,  0x01, szMessage);

		if(nRet < 0)
		{
			printf("GO_Delivery Error : %d\n", nRet);

			return 1;
		}

		nSendedLen -= nSendLen;
		nMessagePos+= nSendedLen;
	}

	return 0;
}

int Init()
{
	if(Initialize(szServerIP, nServerPort, pszDomainCode , pszGWAuthID, GMMP_ON_LOG, nErrorLevel, GMMP_NETWORK_ALYWAYS_OFF, "Log") != 0)
	{
		printf("Server Connect Error\n");

		return 1;
	}

	SetCallFunction( (void*)Recv);
	SetAuthKey(pszAuthKey);
	SetGWID(pszGWID);


	return 0;
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	if(GW_Delivery() != 0)
	{
		printf("GW_Delivery Error");
		return -1;
	}

	if(Device_Delivery() != 0)
	{
		printf("Device_Delivery Error");
		return -1;
	}

	return 0;

}
 @endcode
 */
int GO_Delivery(const char* pszGWID,
		const char* pszDeviceID,
		const char cReportType,
		const char cMediaType,
		const char* pszMessageBody);
/**
 * @}
 */
/**
 * @defgroup GMMP_Control_Operation M2M GW/Device 단말 제어
 * M2M 단말에 대한 특정 제어 명령을 전달하기 위한 절차로서 GMMP에서는 2가지 제어 방식을 지원한다.\n
방식 1) TCP Always On 세션을 가지고 있는 M2M 단말인 경우 해당 세션을 통해 직접 제어 메시지를 전달하는 방식이다.\n
방식 2) SMS 메시지를 통해 제어 명령을 전송하는 방식이다.\n

※ Always ON 단말도 TCP 세션이 끊어져 있는 경우에는 SMS 메시지를 통한 제어 명령을 수신할 수 있다.\n

일반적으로 단말 제어 절차는 3단계로 이루어져 있다.\n
1단계는 단말 제어 메시지를 통해 단말에게 제어 명령을 전달하고 응답하는 절차이다.\n
2단계는 Control Type 에 따른 부가적인(Optional) 절차로서 Profile 정보, 큰 제어 데이터, FTP 정보, Remote Access 정보등을 획득하는 절차이다.\n
3단계는 제어 결과를 플랫폼으로 통보하는 절차로서 단말 제어 결과 보고 메시지를 통해 제어 결과를 플랫폼으로 통보하고 그에 대한 결과를 수신한다.\n

제어절차시 Control Type 에 따라 M2M GW의 Reboot 절차가 수행될 수 있다.\n

단말 제어 메시지의 Control Type은 @ref Define_Control.h의 메시지 타입이 존재하며, 아래의 Control Type인 경우 부가 절차를 따른다.\n
1. @ref CONTROL_Profile_Reset인 경우 @ref GMMP_ProfileInfo_Operation의 기능을 연계\n
2. @ref CONTROL_FW_Download, @ref  CONTROL_App_Download인 경우 @ref GMMP_FTP_Operation의 기능을 연계\n
3. @ref CONTROL_Remote_Access인 경우 @ref GMMP_Remote_Operation의 기능을 연계\n
4. @ref CONTROL_Multimedia_Control_Start인 경우 @ref GMMP_Multimedia_Operation의 기능을 연계

전송 패킷 : @ref Struct_Control.h @ref Struct_Control_Opt.h참조

 * @ingroup GMMP_Control_Operation
 * @{
 */
/**
 *
 * @param pszGWID OMP로 제공 받은 GW ID값.
 * @param pszDeviceID OMP로 제공 받은 Device ID값.
 * @param nTID T-ID는 M2M GW와 OMP 간의 트랜잭션을 구분하기 위한 값으로서 Request 요청하는 곳에서 할당하며 Response 받은 곳에서는 해당 T-ID 값을 그대로 반환한다.\n
				M2M GW와 OMP에서 T-ID 사용 범위는 다음과 같다.\n
				※ M2M GW T-ID : 0 ~ 99,999 (10만개)\n
				※ OMP T-ID : M2M GW가 사용 이외의 값\n
 * @param cControlType Data Collect Period & Time Setting , Reboot, Configuration, Time Sync, Change Server IP/Port(OMP), HB Period, etc\n
 * 				@ref Define_Operation.h 참조
 * @param cResultCode Result Code (0x00 : Success, other : Fail Reason)\n
			@ref OMPErrorCode.h 참조
 *
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 @code GW/Device 제어 샘플 코드 (Sample_Control_TCP_AlwaysOn 샘플 참조)

int Recv(GMMPHeader* pstGMMPHeader, void* pBody)
{
	U8 cMessageType = pstGMMPHeader->ucMessageType;

	if(cMessageType  == OPERATION_PROFILE_RSP)
	{
		stProfileRspHdr* pstRspHdr =(stProfileRspHdr*) pBody;

		if(pstRspHdr->ucResultCode != 0x00)
		{
			printf("ResultCode  : %x - %s\n", pstRspHdr->ucResultCode, GetStringtoOMPErrorCode(pstRspHdr->ucResultCode));

			return 1;
		}

		if(strlen((char*)pstRspHdr->usDeviceID) <= 0) //GW Profile 조회
		{
			//주기값 재설정
			//pstRspHdr->unHeartbeatPeriod;
			//pstRspHdr->unReportOffset;
			//pstRspHdr->unReportPeriod;
			//pstRspHdr->unResponseTimeout;


			ConvertInt cvtInt;
			memcpy(&cvtInt.usInt, pstRspHdr->unHeartbeatPeriod, sizeof(pstRspHdr->unHeartbeatPeriod) );

			cvtInt.sU8 = ltobi(cvtInt.sU8);

			//Profile 요청 수신 값에 Heartbeat 주기 값으로 변경
			if(cvtInt.sU8 > 0)
			{
				nTimerSec = cvtInt.sU8;
			}
		}
		else  //Device Profile 조회
		{
			//주기값 재설정
			//pstRspHdr->unReportOffset;
			//pstRspHdr->unReportPeriod;
			//pstRspHdr->unResponseTimeout;

		}
	}
	else if(pstGMMPHeader->ucMessageType == OPERATION_HEARTBEAT_RSP)
	{
		stHeartBeatMsgReqHdr* pstRspHdr =(stHeartBeatMsgReqHdr*) pBody;


		return 0;
	}

	return 0;
}

void* TimerThread()
{
	//생략
}

void* TCPReadThread(void *data)
{
	//생략
}


int Init()
{
	//생략
}

int GW_Profile()
{
	//생략
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	pthread_t thread_id = 0;
	pthread_t timer_id = 0;

	pthread_create(&thread_id, NULL, TCPReadThread, NULL);
	pthread_create(&timer_id, NULL, TimerThread, NULL);

	pthread_join(thread_id, NULL);
	pthread_join(timer_id, NULL);
	return 0;

}
 @endcode
 */
 int GO_Control(const char* pszGWID,
 		const char* pszDeviceID,
 		long nTID,
 		const char cControlType,
 		const char cResultCode);
/**
 * @}
 */
/**
 * @defgroup GMMP_Notification_Operation M2M GW/Device 제어 결과 보고
 전송 패킷 : @ref Struct_Notification.h 참조
 * 제어 결과를 플랫폼으로 통보하고 그에 대한 결과를 수신한다.
 */
/**
* @ingroup GMMP_Notification_Operation
* @{
*/
/**
 *
  * @param pszGWID OMP로 제공 받은 GW ID값.
 * @param pszDeviceID OMP로 제공 받은 Device ID값.
 * @param cControlType 단말 제어 메시지에 수신한 값과 동일한 값을 사용한다
 * @param cResultCode Result Code (0x00 : Success, other : Fail Reason)
 * @param pszMessageBody Data[2048 Byte]
 * @param nMessageBodySize pszMessageBody의 크기
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 *
 @code GW/Device 제어 결과 보고 샘플 코드 (Sample_Control_TCP_AlwaysOn 샘플 참조)

int Recv(GMMPHeader* pstGMMPHeader, void* pBody)
{
	U8 cMessageType = pstGMMPHeader->ucMessageType;

	if(cMessageType  == OPERATION_PROFILE_RSP)
	{
		stProfileRspHdr* pstRspHdr =(stProfileRspHdr*) pBody;

		if(pstRspHdr->ucResultCode != 0x00)
		{
			printf("ResultCode  : %x - %s\n", pstRspHdr->ucResultCode, GetStringtoOMPErrorCode(pstRspHdr->ucResultCode));

			return 1;
		}

		if(strlen((char*)pstRspHdr->usDeviceID) <= 0) //GW Profile 조회
		{
			//주기값 재설정
			//pstRspHdr->unHeartbeatPeriod;
			//pstRspHdr->unReportOffset;
			//pstRspHdr->unReportPeriod;
			//pstRspHdr->unResponseTimeout;


			int nHeartBeat = Char2int((char*)pstRspHdr->unHeartbeatPeriod); //수신받은 Heartbeat 주기 값을 확인.

			//Profile 요청 수신 값에 Heartbeat 주기 값으로 변경
			if(nHeartBeat > 0)
			{
				nTimerSec = nHeartBeat;
			}
		}
		else  //Device Profile 조회
		{
			//주기값 재설정
			//pstRspHdr->unReportOffset;
			//pstRspHdr->unReportPeriod;
			//pstRspHdr->unResponseTimeout;

		}
	}
	else if(pstGMMPHeader->ucMessageType == OPERATION_HEARTBEAT_RSP)
	{
		stHeartBeatMsgReqHdr* pstRspHdr =(stHeartBeatMsgReqHdr*) pBody;


		return 0;
	}

	return 0;
}

void* TimerThread()
{
	//생략
}

void* TCPReadThread(void *data)
{
	//생략
}


int Init()
{
	//생략
}

int GW_Profile()
{
	//생략
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	pthread_t thread_id = 0;
	pthread_t timer_id = 0;

	pthread_create(&thread_id, NULL, TCPReadThread, NULL);
	pthread_create(&timer_id, NULL, TimerThread, NULL);

	pthread_join(thread_id, NULL);
	pthread_join(timer_id, NULL);
	return 0;

}
 @endcode
 */
int GO_Notifi(const char* pszGWID,
		const char* pszDeviceID,
		const char cControlType,
		const char cResultCode,
		const char* pszMessageBody,
		const int nMessageBodySize);
/**
 * @}
 */

/**
 * @defgroup GMMP_Heartbeat_Operation M2M GW/Device Heartbeat
 TCP Always On 단말인 경우 해당 세션을 감시하기 위해 주기적으로 Heartbeat 메시지를 전송한다.\n
 M2M 단말은 Profile 정보의 Heartbeat Period 값을 주기로 전송하며, 0인 경우에는 세션을 유지하지 않는다.

 전송 패킷 : @ref Struct_Heartbeat.h 참조

 * @ingroup GMMP_Heartbeat_Operation
 * @{
 */

/**
 *
 * @param pszGWID GW ID
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 @code GW/Device Heartbeat 보고 샘플 코드 (Sample_Control_TCP_AlwaysOn 샘플 참조)

int Recv(GMMPHeader* pstGMMPHeader, void* pBody)
{
	U8 cMessageType = pstGMMPHeader->ucMessageType;

	if(cMessageType  == OPERATION_PROFILE_RSP)
	{
		//생략
	}
	else if(pstGMMPHeader->ucMessageType == OPERATION_HEARTBEAT_RSP)
	{
		stHeartBeatMsgReqHdr* pstRspHdr =(stHeartBeatMsgReqHdr*) pBody;


		return 0;
	}

	return 0;
}

void* TimerThread()
{
	int nCount = 0;
	while(bTimer == true)
	{
		if(strlen(pszGWAuthID) > 0 && strlen(pszAuthKey) > 0  )
		{
			SetTID(GetTID()+1);

			int nRet = GMMP_SetHB(pszGWAuthID, pszAuthKey, pszDomainCode, pszGWID);
			if(nRet != GMMP_SUCCESS)
			{
				if(nCount > 2)
				{
					break;
				}
				nCount++;
			}
		}

		sleep(nTimerSec);
	}

	return NULL;
}

void* TCPReadThread(void *data)
{
	//생략
}


int Init()
{
	//생략
}

int GW_Profile()
{
	//생략
}

int main()
{
	if(Init() != 0)
	{
		printf("Init Error");
		return -1;
	}

	pthread_t thread_id = 0;
	pthread_t timer_id = 0;

	pthread_create(&thread_id, NULL, TCPReadThread, NULL);
	pthread_create(&timer_id, NULL, TimerThread, NULL);

	pthread_join(thread_id, NULL);
	pthread_join(timer_id, NULL);
	return 0;

}

 @endcode
 */
int GO_HB(const char* pszGWID);
/**
 * @}
 */

int OG_Reg_Recv(GMMPHeader* pstGMMPHeader, stGwRegistrationRspHdr* pstGWBody, stDeviceRegistrationRspHdr* pstDeviceBody);
int OG_DeReg_Recv(GMMPHeader* pstGMMPHeader, stGwDeRegistrationRspHdr* pstGWBody, stDeviceDeRegistrationRspHdr* pstDeviceBody);
int OG_Profile_Recv(GMMPHeader* pstGMMPHeader, stProfileRspHdr* pstBody);
int OG_Delivery_Recv(GMMPHeader* pstGMMPHeader, stPacketDeliveryRspHdr* pstBody);
int OG_Ctrl_Recv(GMMPHeader* pstGMMPHeader, stControlReqHdr* pstBody);
int OG_HB_Recv(GMMPHeader* pstGMMPHeader, stHeartBeatMsgRspHdr* pstBody);
int OG_Notifi_Recv(GMMPHeader* pstGMMPHeader, stNotificationRspHdr* pstBody);

/**
 * @brief GMMP 라이브러리 초기화 및 기본 정보 입력
 * @param serverIp 접속할 서버 IP, 4 byte array. @ref g_serverIp에 저장된다,
 * @param nPort 접속할 서버 port, @ref g_nServerPort에 저장된다.
 * @param pszDomainCode OMP Portal을 통해 등록된 서비스 코드, @ref g_szDomainCode에 저장된다,
 * @param pszGWAuthID M2M GW 의 Serial Number 값이며, MSISDN 또는 MAC Address값을 사용할 수도 있다. @ref g_szAuthID에 저장된다.
 * @param nGMMPMode 로그 저장 유무, GMMP_OFF_LOG, GMMP_ON_LOG
 * @param nErrorLevel	로그 출력 레벨
 * @param nNetwrokType 통신 타입
 * @param mac MAC Address. 6 byte array.
 * @return 성공 : GMMP_SUCCESS, 실패: 1이상 , 에러코드 참조
 */
int Initialize(byte* serverIp,
		const int nPort,
		const char* pszDomainCode,
		const char* pszGWAuthID,
		byte* mac);

/**
* @brief GMMP 라이브러리 Uninitialize
*/
void Uninitialize();

/**
 * @brief TCP Always On 에서 사용하는 함수\n
 * Thread를 생성 하고 이 함수를 연결하여 사용한다.
 * @param pstGMMPHeader @ref GMMPHeader 구조체 포인트
 * @param pBody Body 메시지 구조체 포인트
 * @return 성공 : GMMMP_SUCCESS, 실패 : @ref ErrorCode.h 참조
 */
int GetReadData(GMMPHeader* pstGMMPHeader, void** pBody);

/**
 *char 타입의 데이터를  int로 변환한다.
 * @param pBuffer in
 * @param nSize in pBuffer size
 * @return int
 */
long Char2int(void* pBuffer, int nSize);

/**
 *char 타입의 데이터를  short로 변환한다.
 * @param pBuffer
 * @param nSize
 * @return
 */
int Char2short(void* pBuffer, int nSize);

/**
 *@fn void InitMemory();
 *@brief 내부 변수 초기화
 */
void InitMemory();

/**
 * @brief OMP로 제공 받은 AuthKey값을 저장하는 함수
 * @param pszAuthKey OMP로 부터 제공 받은 Auth Key 값
 */
void SetAuthKey(const char* pszAuthKey);
/**
 @brief 저장된  AuthKey
 * @return 저장된 Auth Key
 */
char* GetAuthKey();


/**
 * @brief OMP로 제공 받은 GW ID값을 저장하는 함수
 * @param pszGWID OMP로 부터 제공 받은 GW ID 값
 */
void SetGWID(const char* pszGWID);

/**
 *
 * @return 저장된 GW ID
 */
char* GetGWID();

/**
 *@brief 서버 정보 및 GW Auth ID, DomainCode를 저장한다.
 * @param serverIp Server IP
 * @param nPort Server Port
 * @param pszAuthID Auth ID
 * @param pszDomainCode DomainCode
 * @return 성공 : GMMP_SUCCESS, 실패 : LIB_PARAM_ERROR
 */
int SetServerInfo(byte* serverIp, int nPort, const char* pszAuthID, const char* pszDomainCode);

/**
 *@brief OMP서버로 부터 수신한 패킷을 제공할 콜백함수 저장 함수
 * @param pCallFunctionName 콜백을 제공 받을 함수 포인트
 */
void SetCallFunction(int (* pCallFunctionName)(GMMPHeader* pstGMMPHeader, void* pstBody));

#endif /* GMMP_H_ */