MSR Test Application

MSR 정보

Driver Header file

#ifndef	__MMD1100_H__
#define	__MMD1100_H__

#include	<stdint.h>		/* types */

#define	DEVICE_MMD1100								"/dev/ttyS5"
#define	MMD1100_DEFAULT_BAUDRATE					9600
//#define	MMD1100_DEFAULT_BAUDRATE					19200
//#define	MMD1100_DEFAULT_BAUDRATE					38400
//#define	MMD1100_DEFAULT_BAUDRATE					57600
//#define	MMD1100_DEFAULT_BAUDRATE					115200

#define	MMD1100_TIMEOUT_BETWEEN_SERIAL_INPUT_DATA	20 /*20 msec*/

typedef	enum
{
	MMD1100_COMMAND_GET_VERSION = 0,
	MMD1100_COMMAND_LOAD_USER_PARAMETERS,
	MMD1100_COMMAND_UART_CALIBRATION,
	MMD1100_COMMAND_OTP_WRITE,
	MMD1100_COMMAND_GET_STATUS,
	MMD1100_COMMAND_READ_DATA_RETRY,
	MMD1100_COMMAND_SOFTWARE_RESET
} MMD1100_Command_t;

typedef	struct
{
	/* */
	uint8_t	ErrorCodeForTrack1;
	uint8_t	ErrorCodeForTrack2;
	uint8_t	ErrorCodeForTrack3;

	/* */
	uint8_t	LengthOfTrack1;
	uint8_t	LengthOfTrack2;
	uint8_t	LengthOfTrack3;

	/* ISO7813 */
	uint8_t	pTrack1[79 * 2];
	uint8_t	pTrack2[40 * 2];
	uint8_t	pTrack3[107 * 2];

	/* */
	uint8_t	LengthOfRaw1;
	uint8_t	LengthOfRaw2;
	uint8_t	LengthOfRaw3;
	uint8_t	pRaw1[79 * 2];
	uint8_t	pRaw2[40 * 2];
	uint8_t	pRaw3[107 * 2];
} MSRTrack_t;

typedef	struct
{
	MMD1100_Command_t	Command;
	uint8_t				ErrorCode;
	uint8_t				pData[100];
} MMD1100Response_t;


/*	open serial device for cummunication with MMD1100
return:
	-1:	Fail to operation
	-2:	Input Paramters Error
	0:	OK
*/
extern	int				mmd1100_open(int *pDeviceFileDescriptor);

/*	close serial device for end of cummunication with MMD1100
return:
	-1:	Fail to operation
	0:	OK
*/
extern	int				mmd1100_close(void);


/*	serial buffer flush for cummunication with MMD1100
*/
extern	void			mmd1100_serial_flush(void);



/*	get serial device file descriptor for cummunication with MMD1100
return:
	-1:	Fail to operation
	-2:	Input Paramters Error
	0:	OK
*/
extern	int				mmd1100_get_device_file_descriptor(int *pDeviceFileDescriptor);

/*	receive
return:
	-1:	Fail to operation
	-2:	Input Parameter Error
	-4: Timeout or Not Ready
	0:	OK
*/
extern	int				mmd1100_receive(MSRTrack_t *pMSRTrack,
								MMD1100Response_t *pResponse,
								uint32_t *pIsNotTrack,
								uint32_t ResponseTimeout);

/*
	-1: invalid parameter
	0 : OK
*/
extern	int				mmd1100_make_packet(uint8_t *pPacket,
									uint32_t *pMakedPacketByteLength,
									MMD1100_Command_t Command,
									uint8_t pArguments[4]);
/*

	-1: invalid parameter
	-2: send error
	0 : Not open
	+ : Send length
*/
extern	int				mmd1100_send(uint8_t *pPacket,
								uint8_t PacketByteLength);

#endif	/* __MMD1100_H__ */

Driver Source File

#include	<stdint.h>			/* types */
#include	<stdio.h>			/* printf */
#include	<string.h>			/* memcpy, strlen... */
#include	<termios.h>			/* struct termios */
#include	<unistd.h>			/* for open/close .. */
#include	<fcntl.h>			/* for O_RDWR */
#include	<sys/ioctl.h>		/* for ioctl */
#include	<poll.h>			/* struct pollfd */
#include	<time.h>			/* struct timespec */
#include	"CRC_LRC.h"			/* lrc_xor() */
#include	"MemoryControl.h"	/* memory_pick_up_bit() */

#include	"MMD1100.h"		/*  */

#define	MMD1100_DEBUG(fmt, args ...)	printf("DEBUG:%s(%d): " fmt, __FUNCTION__,__LINE__, ## args)
#define	MMD1100_ERROR(fmt, args ...)	printf("ERROR:%s(%d): " fmt, __FUNCTION__,__LINE__, ## args)
#define	MMD1100_INFO(fmt, args ...)		printf("INFOs:%s(%d): " fmt, __FUNCTION__,__LINE__, ## args)

#define	MMD1100_BYTE_SIZE_OF_BUFFER_FOR_SERIAL				512
#define	MMD1100_BYTE_SIZE_OF_BUFFER_FOR_PACKET				1024

#define	MMD1100_PACKET_POSITION_STX							0
#define	MMD1100_PACKET_POSITION_CLASS						1
#define	MMD1100_PACKET_POSITION_FUNCTION					2
#define	MMD1100_PACKET_POSITION_LENGTH						3
#define	MMD1100_PACKET_POSITION_STATUS						4
#define	MMD1100_PACKET_POSITION_DATA_START					5
#define	MMD1100_PACKET_POSITION_TRACK_ID					2

#define	MMD1100_DEFINE_STX									0x02
#define	MMD1100_DEFINE_ETX									0x03
#define	MMD1100_DEFINE_TRACK_DATA							0x33
#define	MMD1100_DEFINE_TRACK_ID_1							0x25
//#define	MMD1100_DEFINE_TRACK_ID_2							0x3F
//#define	MMD1100_DEFINE_TRACK_ID_3							0x5E
#define	MMD1100_DEFINE_TRACK_ID_2							0x5E	/*Bug Fix*/
#define	MMD1100_DEFINE_TRACK_ID_3							0x3F	/*Bug Fix*/

#define	MMD1100_DEFINE_ACK									0x06
#define	MMD1100_DEFINE_NAK									0x15

#define	MMD1100_COMMAND_CLASS_GET_VERSION					0x10
#define	MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS			0x12
#define	MMD1100_COMMAND_CLASS_UART_CALIBRATION				0x13
#define	MMD1100_COMMAND_CLASS_OTP_WRITE						0x15
#define	MMD1100_COMMAND_CLASS_GET_STATUS					0x16
#define	MMD1100_COMMAND_CLASS_READ_DATA_RETRY				0x17
#define	MMD1100_COMMAND_CLASS_SOFTWARE_RESET				0x18

#define	MMD1100_COMMAND_FUNCTION_GET_VERSION				0x31
#define	MMD1100_COMMAND_FUNCTION_LOAD_USER_PARAMETERS		0x31
#define	MMD1100_COMMAND_FUNCTION_UART_CALIBRATION			0x31
#define	MMD1100_COMMAND_FUNCTION_OTP_WRITE					0x33
#define	MMD1100_COMMAND_FUNCTION_GET_STATUS					0x31
#define	MMD1100_COMMAND_FUNCTION_READ_DATA_RETRY			0x31
#define	MMD1100_COMMAND_FUNCTION_SOFTWARE_RESET				0x31

#define	MMD1100_COMMAND_LENGTH_GET_VERSION					0x00
#define	MMD1100_COMMAND_LENGTH_LOAD_USER_PARAMETERS			0x04
#define	MMD1100_COMMAND_LENGTH_UART_CALIBRATION				0x05
#define	MMD1100_COMMAND_LENGTH_OTP_WRITE					0x00
#define	MMD1100_COMMAND_LENGTH_GET_STATUS					0x00
#define	MMD1100_COMMAND_LENGTH_READ_DATA_RETRY				0x00
#define	MMD1100_COMMAND_LENGTH_SOFTWARE_RESET				0x00

#define	MMD1100_RESPONSE_ACK_LENGTH_GET_VERSION				0x10
#define	MMD1100_RESPONSE_ACK_LENGTH_LOAD_USER_PARAMETERS	0x04
#define	MMD1100_RESPONSE_ACK_LENGTH_UART_CALIBRATION		0x01
#define	MMD1100_RESPONSE_ACK_LENGTH_OTP_WRITE				0x01
#define	MMD1100_RESPONSE_ACK_LENGTH_GET_STATUS				0x06

#define	MMD1100_RESPONSE_NAK_LENGTH							0x01

typedef	enum
{
	MMD1100_PACKET_CHECK_STATE_STX = 0,
	MMD1100_PACKET_CHECK_STATE_MODE_CLASS,
	MMD1100_PACKET_CHECK_STATE_TRACK_ID,
	MMD1100_PACKET_CHECK_STATE_TRACK_LENGTH,
	MMD1100_PACKET_CHECK_STATE_TRACK_STATE,
	MMD1100_PACKET_CHECK_STATE_TRACK_DATA,
	MMD1100_PACKET_CHECK_STATE_FUNCTION,
	MMD1100_PACKET_CHECK_STATE_LENGTH,
	MMD1100_PACKET_CHECK_STATE_STATUS,
	MMD1100_PACKET_CHECK_STATE_DATA,
	MMD1100_PACKET_CHECK_STATE_ETX,
	MMD1100_PACKET_CHECK_STATE_BCC
} MMD1100PacketCheckState_t;


typedef	struct
{
	/* Device File Descriptor */
	int							Device;

	struct	termios				BackupTerminalInfo;

	/* Serial Receive Buffer */
	uint8_t						pBufferForSerial[MMD1100_BYTE_SIZE_OF_BUFFER_FOR_SERIAL];
	uint32_t					HeadPointerForSerial;
	uint32_t					TailPointerForSerial;

	/* Received Packet Buffer */
	uint8_t						pBufferForPacket[MMD1100_BYTE_SIZE_OF_BUFFER_FOR_PACKET];
	uint32_t					PacketOffset;
	MMD1100PacketCheckState_t	PacketCheckState;
	uint32_t					DataLengthInPacket;
	uint32_t					PacketLength;

} MMD1100context_t;

static	MMD1100context_t	MMD1100context =
{
	/* Device File Descriptor */
	.Device = -1,

/*	struct	termios				BackupTerminalInfo*/

	/* Serial Receive Buffer */
	.pBufferForSerial = {0},
	.HeadPointerForSerial = 0,
	.TailPointerForSerial = 0,

	/* Received Packet Buffer */
	.pBufferForPacket = {0},
	.PacketOffset = 0,
	.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STX,
	.DataLengthInPacket = 0,
	.PacketLength = 0
};

/* 5 bit (Data + Parity) ANSI/ISO BCD Data Format convert to 8 bit ASCII */
static	const	uint8_t		pDataFormatTableForISO_BCD[] =
{
/*  0x00	0x01	0x02	0x03	0x04	0x05	0x06	0x07	*/
	' ',	'1',	'2',	' ',	'4',	' ',	' ',	'7',
/*	0x08	0x09	0x0A	0x0B	0x0C	0x0D	0x0E	0x0F	*/
	'8',	' ',	' ',	';',	' ',	'=',	'>',	' ',
/*  0x10	0x11	0x12	0x13	0x14	0x15	0x16	0x17	*/
	'0',	' ',	' ',	'3',	' ',	'5',	'6',	' ',
/*	0x18	0x19	0x1A	0x1B	0x1C	0x1D	0x1E	0x1F	*/
	' ',	'9',	':',	' ',	'<',	' ',	' ',	'?'
};

/* 7 bit (Data + Parity) ANSI/ISO ALPHA Data Format convert to 8 bit ASCII */
static	const	uint8_t		pDataFormatTableForISO_ALPHA[] =
{
/*  0x00	0x01	0x02	0x03	0x04	0x05	0x06	0x07	*/
	0x00,	'!',	'"',	0x00,	'$',	0x00,	0x00,	'\'',
/*	0x08	0x09	0x0A	0x0B	0x0C	0x0D	0x0E	0x0F	*/
	'(',	0x00,	0x00,	'+',	0x00,	'-',	'.',	0x00,
/*  0x10	0x11	0x12	0x13	0x14	0x15	0x16	0x17	*/
	'0',	0x00,	0x00,	'3',	0x00,	'5',	'6',	0x00,
/*	0x18	0x19	0x1A	0x1B	0x1C	0x1D	0x1E	0x1F	*/
	0x00,	'9',	':',	0x00,	'<',	0x00,	0x00,	'?',
/*  0x20	0x21	0x22	0x23	0x24	0x25	0x26	0x27	*/
	'@',	0x00,	0x00,	'C',	0x00,	'E',	'F',	0x00,
/*	0x28	0x29	0x2A	0x2B	0x2C	0x2D	0x2E	0x2F	*/
	0x00,	'I',	'J',	0x00,	'L',	0x00,	0x00,	'O',
/*  0x30	0x31	0x32	0x33	0x34	0x35	0x36	0x37	*/
	0x00,	'Q',	'R',	0x00,	'T',	0x00,	0x00,	'W',
/*	0x38	0x39	0x3A	0x3B	0x3C	0x3D	0x3E	0x3F	*/
	'X',	0x00,	0x00,	'[',	0x00,	'D',	'^',	0x00,
/*  0x40	0x41	0x42	0x43	0x44	0x45	0x46	0x47	*/
	' ',	0x00,	0x00,	'#',	0x00,	'%',	'&',	0x00,
/*	0x48	0x49	0x4A	0x4B	0x4C	0x4D	0x4E	0x4F	*/
	0x00,	')',	'*',	0x00,	',',	0x00,	0x00,	'/',
/*  0x50	0x51	0x52	0x53	0x54	0x55	0x56	0x57	*/
	0x00,	'1',	'2',	0x00,	'4',	0x00,	0x00,	'7',
/*	0x58	0x59	0x5A	0x5B	0x5C	0x5D	0x5E	0x5F	*/
	'8',	0x00,	0x00,	0x00,	0x00,	'=',	'>',	0x00,
/*  0x60	0x61	0x62	0x63	0x64	0x65	0x66	0x67	*/
	0x00,	'A',	'B',	0x00,	'D',	0x00,	0x00,	'G',
/*	0x68	0x69	0x6A	0x6B	0x6C	0x6D	0x6E	0x6F	*/
	'H',	0x00,	0x00,	'K',	0x00,	'M',	'N',	0x00,
/*  0x70	0x71	0x72	0x73	0x74	0x75	0x76	0x77	*/
	'P',	0x00,	0x00,	'S',	0x00,	'U',	'V',	0x00,
/*	0x78	0x79	0x7A	0x7B	0x7C	0x7D	0x7E	0x7F	*/
	0x00,	'Y',	'Z',	0x00,	'\\',	0x00,	0x00,	'_'
};

static	int		mmd100_convert_rawdata_to_bcd(	uint8_t *pTarget,
												uint8_t *pSource,
												uint32_t ByteLengthOfSource,
												int StartFromLast)
{
	uint32_t	TotalBitInMemory;
	uint32_t	BitPositionInMemory;
	uint32_t	BitPositionInBCD;
	int			ByteLengthOfConvertedBCD;
	int			FirstHighBitPosition;
	int			IsERROR;
	uint8_t		BCD;

	if ( ( pTarget == (uint8_t *)0) ||	( pSource == (uint8_t *)0 ) )
	{
		return	-1;
	}

	FirstHighBitPosition = -1;
	TotalBitInMemory = ByteLengthOfSource * 8;
	BCD = 0;
	IsERROR = 0;
	for ( BitPositionInMemory = 0; BitPositionInMemory < TotalBitInMemory; BitPositionInMemory++)
	{
		BCD >>= 1;
		if ( memory_pick_up_bit( (void *)pSource,
								TotalBitInMemory,
								BitPositionInMemory,
								StartFromLast) == 1 )
		{
			if ( FirstHighBitPosition == -1 )
			{
				FirstHighBitPosition = BitPositionInMemory;
			}
			BCD |= 0x10;
		}
		else
		{
			BCD &= 0xEF;
		}
		BCD &= 0x1F;

		if ( BCD == 0x0B/* ';' = SS */ )
		{
			if (FirstHighBitPosition + 4 != BitPositionInMemory) 
			{
				IsERROR = 1;	/* SS error */
			}
			/* get sync */
			break;
		}
	}
	BitPositionInMemory++;	/* skip parity bit for sync char */
	if(BitPositionInMemory >= TotalBitInMemory)
	{
		return	-2;	/* Not find SS */
	}

	ByteLengthOfConvertedBCD = 0;
	pTarget[ByteLengthOfConvertedBCD++] = pDataFormatTableForISO_BCD[0x0B];	/* ';' = SS */

	/* gather data */
    BitPositionInBCD=0;
    BCD = 0;
	for ( ; BitPositionInMemory < TotalBitInMemory; BitPositionInMemory++)
	{
        BCD |= (memory_pick_up_bit( (void *)pSource,
							TotalBitInMemory,
							BitPositionInMemory,
							StartFromLast) << BitPositionInBCD);
		BitPositionInBCD ++;
		if ( BitPositionInBCD == 5 )
		{
			pTarget[ByteLengthOfConvertedBCD++] = pDataFormatTableForISO_BCD[BCD];
		    BitPositionInBCD=0;
		    BCD = 0;
		}
	}

	return	ByteLengthOfConvertedBCD;
}


static	void	mmd1100_packet_flush_buffer(void);


/*	open serial device for cummunication with MMD1100
return:
	-1:	Fail to operation
	-2:	Input Paramters Error
	0:	OK
*/
int				mmd1100_open(int *pDeviceFileDescriptor)
{
	struct termios TerminalInfo;

	if ( pDeviceFileDescriptor == (int *)0 )
	{
		return	-2;
	}

	if ( MMD1100context.Device < 0 )
	{
		/* Initial Serial Receive Buffer */
		MMD1100context.HeadPointerForSerial = 0;
		MMD1100context.TailPointerForSerial = 0;

		/* Initial Received Packet Buffer */
		mmd1100_packet_flush_buffer();

		/* 화일을 연다. */
		MMD1100context.Device = open( DEVICE_MMD1100, (O_RDWR | O_NOCTTY) );
		if ( MMD1100context.Device < 0 )
		{
			/* 화일 열기 실패 */
			MMD1100_ERROR( "failed to open %s\n", DEVICE_MMD1100 );
			MMD1100context.Device = -1;
			*pDeviceFileDescriptor = MMD1100context.Device;
			return	-1;
		}
		/* 현재 설정을 BackupTerminalInfo에 저장 */
		tcgetattr( MMD1100context.Device, &MMD1100context.BackupTerminalInfo );

		memset( &TerminalInfo, 0, sizeof(TerminalInfo) );
		switch( MMD1100_DEFAULT_BAUDRATE )
		{
		case	19200:
			TerminalInfo.c_cflag = B19200 | CS8 | CSTOPB | CLOCAL | CREAD ; 
			break;
		case	38400:
			TerminalInfo.c_cflag = B38400 | CS8 | CSTOPB | CLOCAL | CREAD ; 
			break;
		case	57600:
			TerminalInfo.c_cflag = B57600 | CS8 | CSTOPB | CLOCAL | CREAD ; 
			break;
		case	115200:
			TerminalInfo.c_cflag = B115200 | CS8 | CSTOPB | CLOCAL | CREAD ; 
			break;
		case	9600:
		default:
			TerminalInfo.c_cflag = B9600 | CS8 | CSTOPB | CLOCAL | CREAD ; 
			break;
		}
		TerminalInfo.c_iflag = 0; /* IGNPAR? */
		TerminalInfo.c_oflag = 0;
		//set input mode (non-canonical, no echo,.....)
		TerminalInfo.c_lflag = 0;
		TerminalInfo.c_cc[VTIME] = 30;	/* time-out 값으로 사용된다. time-out 값은 TIME*0.1초 이다. */
		TerminalInfo.c_cc[VMIN]  = 0;	/* MIN은 read가 리턴되기 위한 최소한의 문자 개수 */

		tcflush(MMD1100context.Device, TCIFLUSH);

		tcsetattr(MMD1100context.Device, TCSANOW, &TerminalInfo);

		//	raw mode
		fcntl(MMD1100context.Device, F_SETFL, O_NONBLOCK);
	}
	else
	{
		MMD1100_DEBUG("%s already opened\n", DEVICE_MMD1100);
	}
	*pDeviceFileDescriptor = MMD1100context.Device;

	return	0;
}


/*	close serial device for end of cummunication with MMD1100
return:
	-1:	Fail to operation
	0:	OK
*/
int				mmd1100_close(void)
{
	if ( MMD1100context.Device < 0 )
	{
		MMD1100_ERROR("%s already closed\n", DEVICE_MMD1100);
		return	-1;
	}
	/* 이전 상태로 되돌린다. */
	tcsetattr( MMD1100context.Device, TCSANOW, &MMD1100context.BackupTerminalInfo );

	close(MMD1100context.Device);

	MMD1100context.Device = -1;

	return	0;
}


/*	get serial device file descriptor for cummunication with MMD1100
return:
	-1:	Fail to operation
	-2:	Input Paramters Error
	0:	OK
*/
int				mmd1100_get_device_file_descriptor(int *pDeviceFileDescriptor)
{
	if ( pDeviceFileDescriptor == (int *)0 )
	{
		return	-2;
	}
	if ( MMD1100context.Device != -1 )
	{
		*pDeviceFileDescriptor = MMD1100context.Device;
		return	0;
	}
	MMD1100_ERROR("%s is closed\n", DEVICE_MMD1100);

	return	-1;
}


/*	serial buffer flush for cummunication with MMD1100
*/
void			mmd1100_serial_flush(void)
{
	struct	pollfd	PollFileDescriptor;
	int				Result;
	uint8_t			ReceivedByte;

	if ( MMD1100context.Device != -1 )
	{
		memset( &PollFileDescriptor, 0, sizeof(struct pollfd) );
		while(1)
		{
			PollFileDescriptor.fd = MMD1100context.Device;
			PollFileDescriptor.events = POLLIN;
			PollFileDescriptor.revents = 0;

			Result = poll( &PollFileDescriptor, 1, 2 ); //	2 msec

			if ( (Result == 1) && ((PollFileDescriptor.revents & POLLIN) != 0) )
			{
				read(MMD1100context.Device, &ReceivedByte, 1);
			}
			else
			{
				break;
			}
		}
	}
	else
	{
		MMD1100_ERROR("%s is closed\n", DEVICE_MMD1100);
	}
	MMD1100context.HeadPointerForSerial = 0;
	MMD1100context.TailPointerForSerial = 0;
}


/*	send data(n byte) to MMD1100 through serial device
*/
static	void	mmd1100_serial_transmit_data(uint8_t *pData, uint32_t ByteLengthOfData)
{
	int		Result;
	uint8_t	Byte;

	while(ByteLengthOfData--)
	{
		Byte = *pData++;
		do
		{
			Result = write(MMD1100context.Device, &Byte, 1);
		} while( Result != 1 );
	}
}


/*	polling serial device to save input data from MMD1100
*/
static	void	mmd1100_serial_polling(void)
{
	struct	pollfd	PollFileDescriptor;
	uint32_t		Temp;
	int				Result;
	uint8_t			ReceivedByte;

	memset( &PollFileDescriptor, 0, sizeof(struct pollfd) );
	PollFileDescriptor.fd = MMD1100context.Device;
	PollFileDescriptor.events = POLLIN;
	PollFileDescriptor.revents = 0;

	Result = poll( (struct pollfd *)&PollFileDescriptor, 1, 20);	//	20 msec

	if ( (Result == 1) && ((PollFileDescriptor.revents & POLLIN) != 0) )
	{
		if ( read(MMD1100context.Device, &ReceivedByte, 1) == 1 )
		{
			MMD1100context.pBufferForSerial[MMD1100context.HeadPointerForSerial] = ReceivedByte;
			Temp = (MMD1100context.HeadPointerForSerial + 1) % MMD1100_BYTE_SIZE_OF_BUFFER_FOR_SERIAL;
			if ( Temp != MMD1100context.TailPointerForSerial )
			{
				MMD1100context.HeadPointerForSerial = Temp;
			}
		}
	}
}


/*	check serial buffer to find received data from MMD1100
return:
	0:	Data is not received 
	1:	Data received
*/
static	int		mmd1100_serial_check_buffer(void)
{
	//	check lowlevel serial data, if we have no data
	if ( MMD1100context.HeadPointerForSerial == MMD1100context.TailPointerForSerial )
	{
		mmd1100_serial_polling();
	}

	if ( MMD1100context.HeadPointerForSerial != MMD1100context.TailPointerForSerial )
	{
		return	1;
	}

	return	0;
}


/*	get data from serial buffer
return:
	-1:	Fail to operation
	-2:	Input Paramters Error
	0:	OK
*/
static	int		mmd1100_serial_get_data_from_buffer(uint8_t *pData)
{
	if ( pData == (uint8_t *)0 )
	{
		return	-2;
	}
	if ( MMD1100context.TailPointerForSerial == MMD1100context.HeadPointerForSerial)
	{
		return	-1;
	}
	
	*pData = MMD1100context.pBufferForSerial[MMD1100context.TailPointerForSerial];
	MMD1100context.TailPointerForSerial++;
	MMD1100context.TailPointerForSerial %= MMD1100_BYTE_SIZE_OF_BUFFER_FOR_SERIAL;

	return	0;
}


/*	flush received packet buffer
*/
static	void	mmd1100_packet_flush_buffer(void)
{
	MMD1100context.PacketOffset = 0;
	MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STX;
}


/*
	-1: invalid
	0 : OK
*/
static	int		mmd1100_check_response(uint8_t Class,
										uint8_t Function,
										uint8_t Length,
										uint8_t Status)
{
	switch (Class)
	{
	case	MMD1100_COMMAND_CLASS_GET_VERSION:
		if ( Function == MMD1100_COMMAND_FUNCTION_GET_VERSION )
		{
			if ( ( ( Status == MMD1100_DEFINE_ACK ) && ( Length == MMD1100_RESPONSE_ACK_LENGTH_GET_VERSION ) )
			  || ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) ) )
			{
				return	0;
			}
		}
		break;

	case	MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS:
		if ( Function == MMD1100_COMMAND_FUNCTION_LOAD_USER_PARAMETERS )
		{
			if ( ( ( Status == MMD1100_DEFINE_ACK ) && ( Length == MMD1100_RESPONSE_ACK_LENGTH_LOAD_USER_PARAMETERS ) )
			  || ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) ) )
			{
				return	0;
			}
		}
		break;

	case	MMD1100_COMMAND_CLASS_UART_CALIBRATION:
		if ( Function == MMD1100_COMMAND_FUNCTION_UART_CALIBRATION )
		{
			if ( ( ( Status == MMD1100_DEFINE_ACK ) && ( Length == MMD1100_RESPONSE_ACK_LENGTH_UART_CALIBRATION ) )
			  || ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) ) )
			{
				return	0;
			}
		}
		break;

	case	MMD1100_COMMAND_CLASS_OTP_WRITE:
		if ( Function == MMD1100_COMMAND_FUNCTION_OTP_WRITE )
		{
			if ( ( ( Status == MMD1100_DEFINE_ACK ) && ( Length == MMD1100_RESPONSE_ACK_LENGTH_OTP_WRITE ) )
			  || ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) ) )
			{
				return	0;
			}
		}
		break;

	case	MMD1100_COMMAND_CLASS_GET_STATUS:
		if ( Function == MMD1100_COMMAND_FUNCTION_GET_STATUS )
		{
			if ( ( ( Status == MMD1100_DEFINE_ACK ) && ( Length == MMD1100_RESPONSE_ACK_LENGTH_GET_STATUS ) )
			  || ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) ) )
			{
				return	0;
			}
		}
		break;

	case	MMD1100_COMMAND_CLASS_READ_DATA_RETRY:
		if ( Function == MMD1100_COMMAND_FUNCTION_READ_DATA_RETRY )
		{
			if ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) )
			{
				return	0;
			}
		}
		break;

	case	MMD1100_COMMAND_CLASS_SOFTWARE_RESET:
		if ( Function == MMD1100_COMMAND_FUNCTION_SOFTWARE_RESET )
		{
			if ( ( Status == MMD1100_DEFINE_NAK ) && ( Length == MMD1100_RESPONSE_NAK_LENGTH ) )
			{
				return	0;
			}
		}
		break;

	default:
		break;
	}

	return	-1;
}

/*	make response packet form serial buffer
return:
	2:	Notify Packet
	1:	Need Time Wait
	-1:	Fail to operation
	-2:	Packet LRC Error
	-3: Packet Data is too Big
	-4: Timeout or Not Ready
	0:	OK
*/
static int		mmd1100_packet_make_response_from_serial_buffer(void)
{
	struct	timespec	CurrentTime;
	struct	timespec	GetTimeToLastData;
	uint8_t				Data;

	while( mmd1100_serial_check_buffer() == 1 )
	{	/* Serial buffer has data */
		mmd1100_serial_get_data_from_buffer( &Data );

		clock_gettime( CLOCK_REALTIME, &GetTimeToLastData );

		/* Push Data to Packet Buffer */
		MMD1100context.pBufferForPacket[MMD1100context.PacketOffset] = Data;
/*
printf("0x%02X ", Data);
*/
		if ( MMD1100context.PacketOffset < MMD1100_BYTE_SIZE_OF_BUFFER_FOR_PACKET )
		{
			MMD1100context.PacketOffset++;
		}

		switch( MMD1100context.PacketCheckState )
		{
		case	MMD1100_PACKET_CHECK_STATE_STX:
			if ( Data == MMD1100_DEFINE_STX )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_MODE_CLASS;
			}
			else
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_DEBUG( "invalid received Data : 0x%02X\n", Data );
				return	-1;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_MODE_CLASS:
			MMD1100context.PacketLength = 0;
			if ( Data == MMD1100_DEFINE_TRACK_DATA )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_TRACK_ID;
			}
			else
			{
				switch ( Data )
				{
				case	MMD1100_COMMAND_CLASS_GET_VERSION:
				case	MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS:
				case	MMD1100_COMMAND_CLASS_UART_CALIBRATION:
				case	MMD1100_COMMAND_CLASS_OTP_WRITE:
				case	MMD1100_COMMAND_CLASS_GET_STATUS:
				case	MMD1100_COMMAND_CLASS_READ_DATA_RETRY:
				case	MMD1100_COMMAND_CLASS_SOFTWARE_RESET:
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_FUNCTION;
					break;
				default:
					mmd1100_packet_flush_buffer();
					//	invaild command sequence
					MMD1100_DEBUG( "invalid received Data : 0x%02X\n", Data );
					return	-1;
					break;
				}
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_TRACK_ID:
			if ( ( Data == MMD1100_DEFINE_TRACK_ID_1 )
			  || ( Data == MMD1100_DEFINE_TRACK_ID_2 )
			  || ( Data == MMD1100_DEFINE_TRACK_ID_3 ) )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_TRACK_LENGTH;
			}
			else if ( Data == MMD1100_DEFINE_ETX )
			{
				MMD1100context.PacketLength += 3;
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_BCC;
			}
			else
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_DEBUG("invalid received Data : 0x%02X\n", Data);
				return	-1;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_TRACK_LENGTH:
			MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_TRACK_STATE;
			MMD1100context.DataLengthInPacket = Data;
			break;

		case	MMD1100_PACKET_CHECK_STATE_TRACK_STATE:
			if ( ( Data == MMD1100_DEFINE_ACK ) || ( Data == MMD1100_DEFINE_NAK ) )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_TRACK_DATA;
				MMD1100context.PacketLength += (MMD1100context.DataLengthInPacket + 3);
			}
			else
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_DEBUG("invalid received Data : 0x%02X\n", Data);
				return	-1;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_TRACK_DATA:
			MMD1100context.DataLengthInPacket--;
			if ( MMD1100context.DataLengthInPacket == 0 )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_TRACK_ID;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_FUNCTION:
			switch ( MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_CLASS] )
			{
			case	MMD1100_COMMAND_CLASS_GET_VERSION:
				if ( Data == MMD1100_COMMAND_FUNCTION_GET_VERSION )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			case	MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS:
				if ( Data == MMD1100_COMMAND_FUNCTION_LOAD_USER_PARAMETERS )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			case	MMD1100_COMMAND_CLASS_UART_CALIBRATION:
				if ( Data == MMD1100_COMMAND_FUNCTION_UART_CALIBRATION )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			case	MMD1100_COMMAND_CLASS_OTP_WRITE:
				if ( Data == MMD1100_COMMAND_FUNCTION_OTP_WRITE )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			case	MMD1100_COMMAND_CLASS_GET_STATUS:
				if ( Data == MMD1100_COMMAND_FUNCTION_GET_STATUS )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			case	MMD1100_COMMAND_CLASS_READ_DATA_RETRY:
				if ( Data == MMD1100_COMMAND_FUNCTION_READ_DATA_RETRY )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			case	MMD1100_COMMAND_CLASS_SOFTWARE_RESET:
				if ( Data == MMD1100_COMMAND_FUNCTION_SOFTWARE_RESET )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_LENGTH;
				}
				break;

			default:
				break;
			}

			if ( MMD1100context.PacketCheckState != MMD1100_PACKET_CHECK_STATE_LENGTH )
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_DEBUG("invalid received Data : 0x%02X\n", Data);
				return	-1;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_LENGTH:
			switch ( MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_CLASS] )
			{
			case	MMD1100_COMMAND_CLASS_GET_VERSION:
				if ( ( Data == MMD1100_RESPONSE_ACK_LENGTH_GET_VERSION )
				  || ( Data == MMD1100_RESPONSE_NAK_LENGTH ) )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			case	MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS:
				if ( ( Data == MMD1100_RESPONSE_ACK_LENGTH_LOAD_USER_PARAMETERS )
				  || ( Data == MMD1100_RESPONSE_NAK_LENGTH ) )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			case	MMD1100_COMMAND_CLASS_UART_CALIBRATION:
				if ( ( Data == MMD1100_RESPONSE_ACK_LENGTH_UART_CALIBRATION )
				  || ( Data == MMD1100_RESPONSE_NAK_LENGTH ) )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			case	MMD1100_COMMAND_CLASS_OTP_WRITE:
				if ( ( Data == MMD1100_RESPONSE_ACK_LENGTH_OTP_WRITE )
				  || ( Data == MMD1100_RESPONSE_NAK_LENGTH ) )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			case	MMD1100_COMMAND_CLASS_GET_STATUS:
				if ( ( Data == MMD1100_RESPONSE_ACK_LENGTH_GET_STATUS )
				  || ( Data == MMD1100_RESPONSE_NAK_LENGTH ) )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			case	MMD1100_COMMAND_CLASS_READ_DATA_RETRY:
				if ( Data == MMD1100_RESPONSE_NAK_LENGTH )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			case	MMD1100_COMMAND_CLASS_SOFTWARE_RESET:
				if ( Data == MMD1100_RESPONSE_NAK_LENGTH )
				{
					MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_STATUS;
				}
				break;

			default:
				break;
			}

			if ( MMD1100context.PacketCheckState != MMD1100_PACKET_CHECK_STATE_STATUS )
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_DEBUG("invalid received Data : 0x%02X\n", Data);
				return	-1;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_STATUS:
			if ( mmd1100_check_response(MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_CLASS]/*Class*/,
										MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_FUNCTION]/*Function*/,
										MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_LENGTH]/*Length*/,
										Data/*Status*/) == 0 )
			{
				MMD1100context.DataLengthInPacket = MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_LENGTH];
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_DATA;
			}
			else
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_DEBUG("invalid received Data : 0x%02X\n", Data);
				return	-1;
			}
			break;
			
		case	MMD1100_PACKET_CHECK_STATE_DATA:
			MMD1100context.DataLengthInPacket--;
			if ( MMD1100context.DataLengthInPacket == 0 )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_ETX;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_ETX:
			if ( Data == MMD1100_DEFINE_ETX )
			{
				MMD1100context.PacketCheckState = MMD1100_PACKET_CHECK_STATE_BCC;
				MMD1100context.PacketLength = 6 + MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_LENGTH];
			}
			else
			{
				mmd1100_packet_flush_buffer();
				//	invaild command sequence
				MMD1100_INFO("invalid received Data : 0x%02X\n", Data);
				return	-1;
			}
			break;

		case	MMD1100_PACKET_CHECK_STATE_BCC:
			mmd1100_packet_flush_buffer();
			MMD1100_DEBUG("received lenght : %d\n", MMD1100context.PacketLength);
			if ( Data == lrc_xor(MMD1100context.pBufferForPacket, MMD1100context.PacketLength) )
			{
				MMD1100_INFO("BCC : OK\n");
				return	0;
			}
			else
			{
				MMD1100_ERROR("BCC : Fail\n");
				return	-2;
			}
			break;
		}
	}

	// check inter-character timeout
	if ( MMD1100context.PacketCheckState != MMD1100_PACKET_CHECK_STATE_STX )
	{
		clock_gettime(CLOCK_REALTIME, &CurrentTime);
		if ( (CurrentTime.tv_nsec - GetTimeToLastData.tv_nsec) > (MMD1100_TIMEOUT_BETWEEN_SERIAL_INPUT_DATA * 1000)/**/ )
		{
			mmd1100_packet_flush_buffer();
//			return	-4;	/* Time out */
		}
	}

	return	-4;	/* Not Ready */
}


/*	receive
return:
	-1:	Fail to operation
	-2:	Input Parameter Error
	-4: Timeout or Not Ready
	0:	OK
*/
int				mmd1100_receive(MSRTrack_t *pMSRTrack,
								MMD1100Response_t *pResponse,
								uint32_t *pIsNotTrack,
								uint32_t ResponseMilisecondTimeout)
{
	struct	timespec	Start;
	struct	timespec	Current;
	uint32_t			Position;
	int					Result;

	if ( pIsNotTrack == (uint32_t *)0 )
	{
		return	-2;
	}

	clock_gettime(CLOCK_REALTIME, &Start);
	while(1)
	{
		Result = mmd1100_packet_make_response_from_serial_buffer();

		if ( Result == -4 )		/* Not ready or time-out */
		{
			clock_gettime(CLOCK_REALTIME, &Current);
			if ( (Current.tv_nsec - Start.tv_nsec) > (ResponseMilisecondTimeout * 1000) )
			{
//				MMD1100_DEBUG("time-out :start - %d nsec, cur = %d nsec, timeout = %d nsec \n", Start, Current, (ResponseMilisecondTimeout * 1000) );
				return	-4;
			}
			continue;
		}

		if ( Result != 0 )
		{
			MMD1100_DEBUG("response_check() return - %d\n", Result);
			return	-1;
		}
		break;
	}

	if( MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_CLASS] == MMD1100_DEFINE_TRACK_DATA)
	{	/* Track Data */
		*pIsNotTrack = 0;
		if ( pMSRTrack == (MSRTrack_t *)0 )
		{
			return	-2;
		}

		memset( pMSRTrack, 0, sizeof(MSRTrack_t) );
		{
			Position = MMD1100_PACKET_POSITION_TRACK_ID;
			while ( MMD1100context.pBufferForPacket[Position] != MMD1100_DEFINE_ETX )
			{
				int	i;
				if ( MMD1100context.pBufferForPacket[Position] == MMD1100_DEFINE_TRACK_ID_1 )
				{
					if ( MMD1100context.pBufferForPacket[Position + 2] == MMD1100_DEFINE_NAK)
					{
						pMSRTrack->ErrorCodeForTrack1 = MMD1100context.pBufferForPacket[Position + 3];
						pMSRTrack->LengthOfTrack1 = 0;
					}
					else
					{
						int temp;
						pMSRTrack->ErrorCodeForTrack1 = 0;
						pMSRTrack->LengthOfTrack1 = 0;

						pMSRTrack->LengthOfRaw1 = MMD1100context.pBufferForPacket[Position + 1];
						memcpy( pMSRTrack->pRaw1, &MMD1100context.pBufferForPacket[Position + 3], pMSRTrack->LengthOfRaw1 );

						temp = mmd100_convert_rawdata_to_bcd(	pMSRTrack->pTrack1,
												&MMD1100context.pBufferForPacket[Position + 3],
												MMD1100context.pBufferForPacket[Position + 1],
												1);
						if (temp > 0)
						{
							pMSRTrack->LengthOfTrack1 = temp;
						}
					}
				}
				if ( MMD1100context.pBufferForPacket[Position] == MMD1100_DEFINE_TRACK_ID_2 )
				{
					if ( MMD1100context.pBufferForPacket[Position + 2] == MMD1100_DEFINE_NAK)
					{
						pMSRTrack->ErrorCodeForTrack2 = MMD1100context.pBufferForPacket[Position + 3];
						pMSRTrack->LengthOfTrack2 = 0;
					}
					else
					{
						int temp;
						pMSRTrack->ErrorCodeForTrack2 = 0;
						pMSRTrack->LengthOfTrack2 = 0;

						pMSRTrack->LengthOfRaw2 = MMD1100context.pBufferForPacket[Position + 1];
						memcpy( pMSRTrack->pRaw2, &MMD1100context.pBufferForPacket[Position + 3], pMSRTrack->LengthOfRaw2 );

						temp = mmd100_convert_rawdata_to_bcd(	pMSRTrack->pTrack2,
												&MMD1100context.pBufferForPacket[Position + 3],
												MMD1100context.pBufferForPacket[Position + 1],
												1);
						if (temp > 0)
						{
							pMSRTrack->LengthOfTrack2 = temp;
						}
						else
						{
							MMD1100_ERROR( " mmd100_convert_rawdata_to_bcd() = -%d", -temp);
						}
					}
				}
				if ( MMD1100context.pBufferForPacket[Position] == MMD1100_DEFINE_TRACK_ID_3 )
				{
					if ( MMD1100context.pBufferForPacket[Position + 2] == MMD1100_DEFINE_NAK)
					{
						pMSRTrack->ErrorCodeForTrack3 = MMD1100context.pBufferForPacket[Position + 3];
						pMSRTrack->LengthOfTrack3 = 0;
					}
					else
					{
						int temp;
						pMSRTrack->ErrorCodeForTrack3 = 0;
						pMSRTrack->LengthOfTrack3 = 0;

						pMSRTrack->LengthOfRaw3 = MMD1100context.pBufferForPacket[Position + 1];
						memcpy( pMSRTrack->pRaw3, &MMD1100context.pBufferForPacket[Position + 3], pMSRTrack->LengthOfRaw3 );

						temp = mmd100_convert_rawdata_to_bcd(	pMSRTrack->pTrack3,
												&MMD1100context.pBufferForPacket[Position + 3],
												MMD1100context.pBufferForPacket[Position + 1],
												1);
						if (temp > 0)
						{
							pMSRTrack->LengthOfTrack3 = temp;
						}
						else
						{
							MMD1100_ERROR( " mmd100_convert_rawdata_to_bcd() = -%d", -temp);
						}
					}
				}
				Position += (3 + MMD1100context.pBufferForPacket[Position + 1]);
			}
		}
	}
	else	/* Response */
	{
		*pIsNotTrack = 1;
		if ( pResponse == (MMD1100Response_t *)0 )
		{
			return	-2;
		}

		memset( pResponse, 0, sizeof(MMD1100Response_t) );
		switch ( MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_CLASS] )
		{
		case	MMD1100_COMMAND_CLASS_GET_VERSION:
			pResponse->Command = MMD1100_COMMAND_GET_VERSION;
			break;
		case	MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS:
			pResponse->Command = MMD1100_COMMAND_LOAD_USER_PARAMETERS;
			break;
		case	MMD1100_COMMAND_CLASS_UART_CALIBRATION:
			pResponse->Command = MMD1100_COMMAND_UART_CALIBRATION;
			break;
		case	MMD1100_COMMAND_CLASS_OTP_WRITE:
			pResponse->Command = MMD1100_COMMAND_OTP_WRITE;
			break;
		case	MMD1100_COMMAND_CLASS_GET_STATUS:
			pResponse->Command = MMD1100_COMMAND_GET_STATUS;
			break;
		case	MMD1100_COMMAND_CLASS_READ_DATA_RETRY:
			pResponse->Command = MMD1100_COMMAND_READ_DATA_RETRY;
			break;
		case	MMD1100_COMMAND_CLASS_SOFTWARE_RESET:
			pResponse->Command = MMD1100_COMMAND_SOFTWARE_RESET;
			break;
		}
		if ( MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_STATUS] == MMD1100_DEFINE_NAK )
		{
			pResponse->ErrorCode = MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_DATA_START];
		}
		else	/* ( MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_STATUS] == MMD1100_DEFINE_ACK ) */
		{
			pResponse->ErrorCode = 0;
			memcpy( pResponse->pData, &MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_DATA_START], MMD1100context.pBufferForPacket[MMD1100_PACKET_POSITION_LENGTH] );
		}
	}

	return	0;
}


/*
	-1: invalid parameter
	0 : OK
*/
int				mmd1100_make_packet(uint8_t *pPacket,
									uint32_t *pMakedPacketByteLength,
									MMD1100_Command_t Command,
									uint8_t pArguments[4])
{
	if((pPacket == (uint8_t *)0) || (pMakedPacketByteLength == (uint32_t *)0))
	{
		return	-1;
	}

	pPacket[0] = MMD1100_DEFINE_STX;	/* STX */
	switch(Command)
	{
	case	MMD1100_COMMAND_GET_VERSION:
		pPacket[1] = MMD1100_COMMAND_CLASS_GET_VERSION;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_GET_VERSION;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_GET_VERSION;	/* Length */
		pPacket[4] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 6;
		pPacket[5] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1));	/* BCC */
		break;

	case	MMD1100_COMMAND_LOAD_USER_PARAMETERS:
		if(pArguments == (uint8_t *)0)
		{
			return	-1;
		}
		pPacket[1] = MMD1100_COMMAND_CLASS_LOAD_USER_PARAMETERS;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_LOAD_USER_PARAMETERS;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_LOAD_USER_PARAMETERS;	/* Length */
		pPacket[4] = pArguments[0];	/* Tx Mode 1 Byte */
		pPacket[5] = pArguments[1];	/* Reserved 1 Byte */
		pPacket[6] = pArguments[2];	/* All Track Error 1 Byte */
		pPacket[7] = pArguments[3];	/* Reserved 1 Byte */
		pPacket[8] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 10;
		pPacket[9] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1));	/* BCC */
		break;

	case	MMD1100_COMMAND_UART_CALIBRATION:
		pPacket[1] = MMD1100_COMMAND_CLASS_UART_CALIBRATION;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_UART_CALIBRATION;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_UART_CALIBRATION;	/* Length */
		pPacket[4] = 0xAA;	/*  */
		pPacket[5] = 0xAA;	/*  */
		pPacket[6] = 0xAA;	/*  */
		pPacket[7] = 0xAA;	/*  */
		pPacket[8] = 0xAA;	/*  */
		pPacket[9] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 11;
		pPacket[10] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1));	/* BCC */
		break;

	case	MMD1100_COMMAND_OTP_WRITE:
		pPacket[1] = MMD1100_COMMAND_CLASS_OTP_WRITE;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_OTP_WRITE;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_OTP_WRITE;	/* Length */
		pPacket[4] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 6;
		pPacket[5] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1));	/* BCC */
		break;

	case	MMD1100_COMMAND_GET_STATUS:
		pPacket[1] = MMD1100_COMMAND_CLASS_GET_STATUS;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_GET_STATUS;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_GET_STATUS;	/* Length */
		pPacket[4] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 6;
		pPacket[5] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1) );	/* BCC */
		break;

	case	MMD1100_COMMAND_READ_DATA_RETRY:
		pPacket[1] = MMD1100_COMMAND_CLASS_READ_DATA_RETRY;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_READ_DATA_RETRY;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_READ_DATA_RETRY;	/* Length */
		pPacket[4] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 6;
		pPacket[5] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1) );	/* BCC */
		break;

	case	MMD1100_COMMAND_SOFTWARE_RESET:
		pPacket[1] = MMD1100_COMMAND_CLASS_SOFTWARE_RESET;	/* Class */
		pPacket[2] = MMD1100_COMMAND_FUNCTION_SOFTWARE_RESET;	/* Function */
		pPacket[3] = MMD1100_COMMAND_LENGTH_SOFTWARE_RESET;	/* Length */
		pPacket[4] = MMD1100_DEFINE_ETX;	/* ETX */
		*pMakedPacketByteLength = 6;
		pPacket[5] = lrc_xor(pPacket, (*pMakedPacketByteLength - 1) );	/* BCC */
		break;

	default:
		return	-1;
		break;
	}

	return	0;
}


/*
	-1: invalid parameter
	-2: send error
	0 : Not open
	+ : Send length
*/
int				mmd1100_send(uint8_t *pPacket,
								uint8_t PacketByteLength)
{
	uint32_t	Index;

	if ( ( pPacket == (uint8_t *)0 ) || ( PacketByteLength == 0 ) )
	{
		return	-1;
	}

	if ( MMD1100context.Device == -1 )
	{
		return	0;
	}

	mmd1100_serial_flush();
	for ( Index = 0; Index < PacketByteLength; Index ++ )
	{
		if ( write( MMD1100context.Device, &pPacket[Index], 1 ) != 1 )
		{
			MMD1100_ERROR( "failed to send packet to MSR controller(MMD1100) %s\n", DEVICE_MMD1100 );
			return	-2;
		}
	}
	tcdrain( MMD1100context.Device );

	return	Index;
}

Test App Source

int						DeviceFileDescriptorForMSR;
MSRTrack_t				MSRTrack;
MMD1100Response_t		MSRResponse;
uint32_t				IsNotTrack;
uint8_t					pVersion[1024];
int						ConvertLength;


....


if ( mmd1100_open( &DeviceFileDescriptorForMSR ) != 0 )
{
	printf("Fail to mmd1100_open\n");
}
else
{
	printf("OK to mmd1100_open\n");
}


....


while( ?? )
{


....


	if ( mmd1100_receive( &MSRTrack, &MSRResponse, &IsNotTrack, 10000/*10ms ResponseTimeout*/) == 0 )
	{
		printf("MSR IN\n");
		if ( IsNotTrack == 1 )
		{
			switch ( MSRResponse.Command )
			{
			case	MMD1100_COMMAND_GET_VERSION:
				if ( MSRResponse.ErrorCode == 0 )
				{
					printf("   MMD1100_COMMAND_GET_VERSION : %s\n", MSRResponse.pData );
				}
				else
				{
					printf("   MMD1100_COMMAND_GET_VERSION : Error = 0x%02X\n", MSRResponse.ErrorCode );
				}
				break;
			case	MMD1100_COMMAND_LOAD_USER_PARAMETERS:
				break;
			case	MMD1100_COMMAND_UART_CALIBRATION:
				break;
			case	MMD1100_COMMAND_OTP_WRITE:
				break;
			case	MMD1100_COMMAND_GET_STATUS:
				break;
			case	MMD1100_COMMAND_READ_DATA_RETRY:
				break;
			case	MMD1100_COMMAND_SOFTWARE_RESET:
				break;
			default:
				break;
			}
		}
		else
		{
			int	i;
			if ( MSRTrack.ErrorCodeForTrack1 == 0 )
			{
				printf( "   Track 1 : " );
				for ( i = 0; i < MSRTrack.LengthOfTrack1; i++ )
				{
					printf( "%c", MSRTrack.pTrack1[i] );
				}
				printf( "\n" );
				if ( ( (MSRTrack.LengthOfTrack1 * 8) % 7 ) == 0 )
				{
					printf( " Length OK \n" );
				}
			}
			else
			{
				printf("   Track 1 : ErrorCode = 0x%02X\n", MSRTrack.ErrorCodeForTrack1 );
			}
			if ( MSRTrack.ErrorCodeForTrack2 == 0 )
			{
				printf( "   Track 2 Raw Data : (Length = %d)\n    ", MSRTrack.LengthOfRaw2 );
				for ( i = 0; i < MSRTrack.LengthOfRaw2; i++ )
				{
					printf( "%02X ", MSRTrack.pRaw2[i] );
				}
				printf( "\n" );
				printf( "   Track 2 : (Length = %d)\n    ", MSRTrack.LengthOfTrack2 );
				for ( i = 0; i < MSRTrack.LengthOfTrack2; i++ )
				{
					printf( "%c", MSRTrack.pTrack2[i] );
				}
				printf( "\n" );
			}
			else
			{
				printf("   Track 2 : ErrorCode = 0x%02X\n", MSRTrack.ErrorCodeForTrack2 );
			}
			if ( MSRTrack.ErrorCodeForTrack3 == 0 )
			{
				printf( "   Track 3 Raw Data : (Length = %d)\n    ", MSRTrack.LengthOfRaw3 );
				for ( i = 0; i < MSRTrack.LengthOfRaw3; i++ )
				{
					printf( "%02X ", MSRTrack.pRaw3[i] );
				}
				printf( "\n" );
				printf( "   Track 3 : (Length = %d)\n    ", MSRTrack.LengthOfTrack3 );
				for ( i = 0; i < MSRTrack.LengthOfTrack3; i++ )
				{
					printf( "%c", MSRTrack.pTrack3[i] );
				}
				printf( "\n" );
			}
			else
			{
				printf("   Track 3 : ErrorCode = 0x%02X\n", MSRTrack.ErrorCodeForTrack3 );
			}
		}
	}


....


}

Result …

MSR IN
 Track 1 : ErrorCode = 0x55
 Track 2 Raw Data : (Length = 31)
  00 00 00 F0 7F 08 21 84 19 C8 14 8D 40 88 10 09 13 DA D9 08 27 61 92 16 02 22 2D 13 0D 00 00
 Track 2 : (Length = 45)
  ;4364200649047469=19042211468940900000??
 Track 3 Raw Data : (Length = 88)
  00 00 00 00 00 00 00 00 00 00 00 00 00 00 90 1F 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 10 42 08 21 84 A0 01 00 00 00 00 00 20
 Track 3 : (Length = 129)
  ;00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000?4

필요 라이브러리 소스

int		memory_pick_up_bit(	void *pMemory,
							uint32_t TotalBitInMemory,
							uint32_t BitPositionInMemory,
							int StartFromLast)
{
	uint8_t *	pByte;

	if ( pMemory == (void *)0 )
	{
		return	-1;
	}

	pByte = (uint8_t *)pMemory;
	if (StartFromLast == 0)
	{
		if ( ( pByte[BitPositionInMemory >> 3] & (0x01 << ( BitPositionInMemory & 0x07 ) ) ) != 0 )
		{
			return	1;
		}
		else
		{
			return	0;
		}
	}
	else
	{
		BitPositionInMemory = TotalBitInMemory - BitPositionInMemory;
		if ( ( pByte[BitPositionInMemory >> 3] & (0x01 << ( BitPositionInMemory & 0x07 ) ) ) != 0 )
		{
			return	1;
		}
		else
		{
			return	0;
		}
	}
}
uint8_t	lrc_xor(uint8_t *pData, uint32_t ByteLength)
{
	uint8_t	LRC = 0;

	while(ByteLength--)
		LRC ^= *pData++;

	return	LRC;
}