API Application Example

API 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__ */

API 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"		/*  */

/*	** ANSI/ISO BCD Data format **

This is a 5-bit Binary Coded Decimal format.
It uses a 16-character set, which uses 4 of the 5 available bits.
The 5th bit is an ODD parity bit, which means there must be an odd number of 1's in
 the 5-bit character..the parity bit will 'force' the total to be odd.
Also, the Least Significant Bits are read FIRST on the strip.

The sum of the 1's in each case is odd, thanks to the parity bit.
If the read system adds up the 5 bits and gets an EVEN number, it flags the read as
 ERROR, and you gotta scan the card again.
(yeah, I *know* a lot of you out there *already* understand parity, but I gotta cover
 all the bases...not everyone sleeps with their modem and can recite the entire AT
 command set at will, you know ;).
See following Figure for details of ANSI/ISO BCD.


ANSI/ISO BCD Data Format

	* Remember that b1 (bit #1) is the LSB (least significant bit)!
	* The LSB is read FIRST!
	* Hexadecimal conversions of the Data Bits are given in parenthesis (xH).

	-Data Bits- Parity
	b1 b2 b3 b4 b5		Character	Function
	0  0  0  0  1		0 (0H)		Data
	1  0  0  0  0		1 (1H)		"
	0  1  0  0  0		2 (2H)		"
	1  1  0  0  1		3 (3H)		"
	0  0  1  0  0		4 (4H)		"
	1  0  1  0  1		5 (5H)		"
	0  1  1  0  1		6 (6H)		"
	1  1  1  0  0		7 (7H)		"
	0  0  0  1  0		8 (8H)		"
	1  0  0  1  1		9 (9H)		"
	0  1  0  1  1		: (AH)		Control
	1  1  0  1  0		; (BH)		Start Sentinel
	0  0  1  1  1		< (CH)		Control
	1  0  1  1  0		= (DH)		Field Separator
	0  1  1  1  0		> (EH)		Control
	1  1  1  1  1		? (FH)		End Sentinel

	***** 16 Character 5-bit Set *****
	10 Numeric Data Characters
	3 Framing/Field Characters
	3 Control Characters

The magstripe begins with a string of Zero bit-cells to permit the self-clocking feature
 of biphase to "sync" and begin decoding.
A "Start Sentinel" character then tells the reformatting process where to start grouping
 the decoded bitstream into groups of 5 bits each.
At the end of the data, an "End Sentinel" is encountered, which is followed by an 
 "Longitudinal Redundancy Check (LRC) character.
The LRC is a parity check for the sums of all b1, b2, b3, and b4 data bits of all preceding
 characters.
The LRC character will catch the remote error that could occur if an individual character 
 had two compensating errors in its bit pattern (which would fool the 5th-bit parity check).

The START SENTINEL, END SENTINEL, and LRC are collectively called "Framing Characters", and
 are discarded at the end of the reformatting process.
*/

/* ** ANSI/ISO ALPHA Data Format **

Alphanumeric data can also be encoded on magstripes.
The second ANSI/ISO data format is ALPHA (alphanumeric) and involves a 7-bit character set
 with 64 characters.
As before, an odd parity bit is added to the required 6 data bits for each of the 64 characters.


ANSI/ISO ALPHA Data Format
	* Remember that b1 (bit #1) is the LSB (least significant bit)!
	* The LSB is read FIRST!
	* Hexadecimal conversions of the Data Bits are given in parenthesis (xH).

		----Data Bits---- Parity
		b1 b2 b3 b4 b5 b6 b7	Character	Function
	40	0  0  0  0  0  0  1		space (0H)	Special
	01	1  0  0  0  0  0  0		! (1H)		"
	02	0  1  0  0  0  0  0		" (2H)		"
	43	1  1  0  0  0  0  1		# (3H)		"
	04	0  0  1  0  0  0  0		$ (4H)		"
		1  0  1  0  0  0  1		% (5H)		Start Sentinel
		0  1  1  0  0  0  1		& (6H)		Special
		1  1  1  0  0  0  0		' (7H)		"
		0  0  0  1  0  0  0		( (8H)		"
		1  0  0  1  0  0  1		) (9H)		"
		0  1  0  1  0  0  1		* (AH)		"
		1  1  0  1  0  0  0		+ (BH)		"
		0  0  1  1  0  0  1		, (CH)		"
		1  0  1  1  0  0  0		- (DH)		"
		0  1  1  1  0  0  0		. (EH)		"
		1  1  1  1  0  0  1		/ (FH)		"
		0  0  0  0  1  0  0		0 (10H)		Data (numeric)
		1  0  0  0  1  0  1		1 (11H)		"
		0  1  0  0  1  0  1		2 (12H)		"
		1  1  0  0  1  0  0		3 (13H)		"
		0  0  1  0  1  0  1		4 (14H)		"
		1  0  1  0  1  0  0		5 (15H)		"
		0  1  1  0  1  0  0		6 (16H)		"
		1  1  1  0  1  0  1		7 (17H)		"
		0  0  0  1  1  0  1		8 (18H)		"
		1  0  0  1  1  0  0		9 (19H)		"
		0  1  0  1  1  0  0		: (1AH)		Special
		1  1  0  1  1  0  1		; (1BH)		"
		0  0  1  1  1  0  0		< (1CH)		"
		1  0  1  1  1  0  1		= (1DH)		"
		0  1  1  1  1  0  1		> (1EH)		"
		1  1  1  1  1  0  0		? (1FH) 	End Sentinel
		0  0  0  0  0  1  0		@ (20H)		Special
		1  0  0  0  0  1  1		A (21H)		Data (alpha)
		0  1  0  0  0  1  1		B (22H)		"
		1  1  0  0  0  1  0		C (23H)		"
		0  0  1  0  0  1  1		D (24H)		"
		1  0  1  0  0  1  0		E (25H)		"
		0  1  1  0  0  1  0		F (26H)		"
		1  1  1  0  0  1  1		G (27H)		"
		0  0  0  1  0  1  1		H (28H)		"
		1  0  0  1  0  1  0		I (29H)		"
		0  1  0  1  0  1  0		J (2AH)		"
		1  1  0  1  0  1  1		K (2BH)		"
		0  0  1  1  0  1  0		L (2CH)		"
		1  0  1  1  0  1  1		M (2DH)		"
		0  1  1  1  0  1  1		N (2EH)		"
		1  1  1  1  0  1  0		O (2FH)		"
		0  0  0  0  1  1  1		P (30H)		"
		1  0  0  0  1  1  0		Q (31H)		" 
		0  1  0  0  1  1  0		R (32H)		"
		1  1  0  0  1  1  1		S (33H)		"
		0  0  1  0  1  1  0		T (34H)		"
		1  0  1  0  1  1  1		U (35H)		"
		0  1  1  0  1  1  1		V (36H)		"
		1  1  1  0  1  1  0		W (37H)		"
		0  0  0  1  1  1  0		X (38H)		"
		1  0  0  1  1  1  1		Y (39H)		"
		0  1  0  1  1  1  1		Z (3AH)		"
		1  1  0  1  1  1  0		[ (3BH)		Special
		0  0  1  1  1  1  1		\ (3DH)		Special
		1  0  1  1  1  1  0		] (3EH)		Special
		0  1  1  1  1  1  0		^ (3FH)		Field Separator
		1  1  1  1  1  1  1		_ (40H)		Special

	***** 64 Character 7-bit Set *****
	* 43 Alphanumeric Data Characters
	* 3 Framing/Field Characters
	* 18 Control/Special Characters

The two ANSI/ISO formats, ALPHA and BCD, allow a great variety of data to be stored on magstripes.
Most cards with magstripes use these formats, but occasionally some do not.
More about those lateron. 
*/

/*	ANSI/ISO Track 1,2,3 Standards

Track	Name	Density		Format	Characters	Function
-----------------------------------------------------------------------------------
1		IATA	210 bpi		ALPHA	79			Read Name & Account
2		ABA		75 bpi		BCD		40			Read Account
3		THRIFT	210 bpi		BCD		107			Read Account & *Encode* Transaction 


This contains an explanation about the format of the three magnetic tracks in standard
 identification cards, particularly those used in financial transactions, i.e., credit
 and debit cards.

It is a summary of the international standards ISO-7813(tracks 1 and 2) and
 ISO-4909(track 3).


Track 1 (IATA)

	Up to 79 ALPHA 7-bit (including parity) characters (alphanumeric) including SS,
	 ES and LRC.
	Read only.
	It comprises the following fields (in this order): 

	SS: Start Sentinel. 1 character: %.

	FC: Format Code. 1 character (alphabetic only):

		A: Reserved for proprietary use of card issuer.
		B: Bank/financial. This is the format described here.
		C-M: Reserved for use by ANSI Subcommittee X3B10.
		N-Z: Available for use by individual card issuers.

	PAN: Primary Account Number. Up to 19 digits:

		In accordance with the account numbering scheme in ISO 7812.

		It consists of the following parts:

			IIN: Issuer Identification Number. Up to 6 digits:

				It consists of the following parts:

				MII: Major Industry Identifier. Up to 2 digits:

					0: Reserved for future use by ISO/TC 68.
					00: Institutions other than card issuers.
					1: Airlines.
					2: Airlines and other future assignments.
					3: Travel and entertainment.
					4: Banking/financial.
					5: Banking/financial.
					59: Financial institutions not registered by ISO.
					6: Merchandising and banking.
					7: Petroleum.
					8: Telecommunications and other future assignments.
					89: Telecommunications administrations and private operating agencies.
					9: Reserved for national use.

				II: Issuer Identifier. Up to 5 digits:

					Identifies the issuer.
					In some cases the first digit indicates the length of the IIN
					 or the responsibility of its assignment outside of ISO.
					If MII = 9 then the first 3 digits should be the country code (CC).

			IAI: Individual Account Identification. Up to 12 digits:

				Assigned by the card issuing institution.

			CD: Check Digit. 1 digit:

				Calculated using the Luhn formula for computing modulus 10
				 "double-add-double" check digit: Double the value of alternate (odd) digits
				 starting by the least significant (first right hand) digit.
				Then add the individual digits of doubled (odd) numbers and even digits of
				 the original number.
				If the value ends in 0 then the check digit is 0.
				Otherwise subtract the value from the next higher number ending in 0
				 (tens complement of the unit digit).
				The result is the check digit.
				Example: If the account number without check digit is 1234 5678 9012 344 then
				 (8) + 4 + (6) + 2 + (2) + 0 + (1 + 8) + 8 + (1 + 4) + 6 + (1 + 0) + 4 + (6)
				  + 2 + (2) = 65, therefore the check digit is 70 - 65 = 5 and so the complete
				  account number is 1234 5678 9012 3445.

		MasterCard PAN is variable up to 16 digits and VISA is 13 or 16 digits, including check digit.

	FS: Field Separator. 1 character: ^.

	CC: Country Code. 3 digits:

		Only if PAN starts with 59 (MasterCard).
		Country codes are defined in ISO 3166: 724 for Spain, 840 for USA, etc.

	NM: Name. 2-26 characters:

		Surname(s) (separated by space if necessary).
		Surname separator: /.
		First name(s) or initial(s) (separated by space if necessary).
		Period (when followed by title).
		Title (when used).

		If this field is not used the content will be an space followed by a surname separator (/).

	FS: Field Separator. 1 character: ^.

	ED: Expiry Date. 4 digits: YYMM.

		If this field is not used a FS will be in place.
		Required by MasterCard and VISA.

	SC: Service Code. 3 digits:

		Digit 1 (most significant): Interchange and technology:

			0: Reserved for future use by ISO.
			1: Available for international interchange.
			2: Available for international interchange and with integrated circuit, which should be used for the financial transaction when feasible.
			3: Reserved for future use by ISO.
			4: Reserved for future use by ISO.
			5: Available for national interchange only, except under bilateral agreement.
			6: Available for national interchange only, except under bilateral agreement, and with integrated circuit, which should be used for the financial transaction when feasible.
			7: Not available for general interchange, except under bilateral agreement.
			8: Reserved for future use by ISO.
			9: Test.

		Digit 2: Authorization processing:

			0: Transactions are authorized following the normal rules.
			1: Reserved for future use by ISO.
			2: Transactions are authorized by issuer and should be online.
			3: Reserved for future use by ISO.
			4: Transactions are authorized by issuer and should be online, except under bilateral agreement.
			5: Reserved for future use by ISO.
			6: Reserved for future use by ISO.
			7: Reserved for future use by ISO.
			8: Reserved for future use by ISO.
			9: Reserved for future use by ISO.

		Digit 3 (least significant): Range of services and PIN requirements:

			0: No restrictions and PIN required.
			1: No restrictions.
			2: Goods and services only (no cash).
			3: ATM only and PIN required.
			4: Cash only.
			5: Goods and services only (no cash) and PIN required.
			6: No restrictions and require PIN when feasible.
			7: Goods and services only (no cash) and require PIN when feasible.
			8: Reserved for future use by ISO.
			9: Reserved for future use by ISO.

		If this field in not used a FS will be in place.
		Required by MasterCard and VISA.

	PVV: Offset or PVV (PIN Verification Value). 5 digits:

		Required by MasterCard and VISA.

	DD: Discretionary Data. Rest of characters:

		Reserved for proprietary use of card issuer.

	ES: End Sentinel. 1 character: ?.

	LRC: Longitude Redundancy Check. 1 character.


Track 2 (ABA)

	Up to 40 BCD 5-bit (including parity) characters (numeric) including SS, ES and LRC.
	Read only.
	It comprises the following fields (in this order):

	SS: Start Sentinel. 1 character: ;.

	PAN: Primary Account Number. Up to 19 digits:

		In accordance with the account numbering scheme in ISO 7812.
		It consists of the following parts:

			IIN: Issuer Identification Number. Up to 6 digits:

				It consists of the following parts:

					MII: Major Industry Identifier. Up to 2 digits:

						0: Reserved for future use by ISO/TC 68.
						00: Institutions other than card issuers.
						1: Airlines.
						2: Airlines and other future assignments.
						3: Travel and entertainment.
						4: Banking/financial.
						5: Banking/financial.
						59: Financial institutions not registered by ISO.
						6: Merchandising and banking.
						7: Petroleum.
						8: Telecommunications and other future assignments.
						89: Telecommunications administrations and private operating agencies.
						9: Reserved for national use.

					II: Issuer Identifier. Up to 5 digits:

						Identifies the issuer. In some cases the first digit indicates the
						 length of the IIN or the responsibility of its assignment outside of ISO.
						If MII = 9 then the first 3 digits should be the country code (CC).

			IAI: Individual Account Identification. Up to 12 digits:

				Assigned by the card issuing institution.

			CD: Check Digit. 1 digit:

				Calculated using the Luhn formula for computing modulus 10
				 "double-add-double" check digit: Double the value of alternate (odd)
				 digits starting by the least significant (first right hand) digit.
				Then add the individual digits of doubled (odd) numbers and even digits
				 of the original number.
				If the value ends in 0 then the check digit is 0.
				Otherwise subtract the value from the next higher number ending in 0
				 (tens complement of the unit digit).
				The result is the check digit.
				Example: If the account number without check digit is 1234 5678 9012 344
				 then (8) + 4 + (6) + 2 + (2) + 0 + (1 + 8) + 8 + (1 + 4) + 6 + (1 + 0)
				 + 4 + (6) + 2 + (2) = 65, therefore the check digit is 70 - 65 = 5 and
				 so the complete account number is 1234 5678 9012 3445.

		MasterCard PAN is variable up to 16 digits and VISA is 13 or 16 digits
		 including check digit.

	FS: Field Separator. 1 character: =.

	CC: Country Code. 3 digits:

		Only if PAN starts with 59 (MasterCard).
		Country codes are defined in ISO 3166: 724 for Spain, 840 for USA, etc.

	ED: Expiry Date. 4 digits: YYMM.

		If this field is not used a FS will be in place.
		Required by MasterCard and VISA.

	SC: Service Code. 3 digits:

		Digit 1 (most significant): Interchange and technology:

			0: Reserved for future use by ISO.
			1: Available for international interchange.
			2: Available for international interchange and with integrated circuit, which should be used for the financial transaction when feasible.
			3: Reserved for future use by ISO.
			4: Reserved for future use by ISO.
			5: Available for national interchange only, except under bilateral agreement.
			6: Available for national interchange only, except under bilateral agreement, and with integrated circuit, which should be used for the financial transaction when feasible.
			7: Not available for general interchange, except under bilateral agreement.
			8: Reserved for future use by ISO.
			9: Test.

		Digit 2: Authorization processing:

			0: Transactions are authorized following the normal rules.
			1: Reserved for future use by ISO.
			2: Transactions are authorized by issuer and should be online.
			3: Reserved for future use by ISO.
			4: Transactions are authorized by issuer and should be online, except under bilateral agreement.
			5: Reserved for future use by ISO.
			6: Reserved for future use by ISO.
			7: Reserved for future use by ISO.
			8: Reserved for future use by ISO.
			9: Reserved for future use by ISO.

		Digit 3 (least significant): Range of services and PIN requirements:

			0: No restrictions and PIN required.
			1: No restrictions.
			2: Goods and services only (no cash).
			3: ATM only and PIN required.
			4: Cash only.
			5: Goods and services only (no cash) and PIN required.
			6: No restrictions and require PIN when feasible.
			7: Goods and services only (no cash) and require PIN when feasible.
			8: Reserved for future use by ISO.
			9: Reserved for future use by ISO.

		If this field in not used a FS will be in place.
		Required by MasterCard and VISA.

	PVV: Offset or PVV (PIN Verification Value). 5 digits:

		Required by MasterCard and VISA.

	DD: Discretionary Data. Rest of characters:

		Reserved for proprietary use of card issuer.

	ES: End Sentinel. 1 character: ?.

	LRC: Longitude Redundancy Check. 1 character.



Track 3 (THRIFT-TTS)

	Up to 107 BCD 5-bit (including parity) characters (numeric) including SS, ES and LRC.
	Read and write.
	It comprises the following fields (in this order): 

	SS: Start Sentinel. 1 character: ;.

	FC: Format Code. 2 digits:

		00: Not valid for international interchange.
		01-02: Bank/financial. These are the formats described here.
		03-19: Reserved for future use by ISO/TC 68.
		20-89: Reserved for future use by ISO/TC 95 SC 17.
		90-99: Reserved for proprietary use of card issuer, but not for international interchange.

	PAN: Primary Account Number. Up to 19 digits:

		In accordance with the account numbering scheme in ISO 7812.
		It consists of the following parts:

		IIN: Issuer Identification Number. Up to 6 digits:

			It consists of the following parts:

				MII: Major Industry Identifier. Up to 2 digits:

					0: Reserved for future use by ISO/TC 68.
					00: Institutions other than card issuers.
					1: Airlines.
					2: Airlines and other future assignments.
					3: Travel and entertainment.
					4: Banking/financial.
					5: Banking/financial.
					59: Financial institutions not registered by ISO.
					6: Merchandising and banking.
					7: Petroleum.
					8: Telecommunications and other future assignments.
					89: Telecommunications administrations and private operating agencies.
					9: Reserved for national use.

				II: Issuer Identifier. Up to 5 digits:

					Identifies the issuer.
					In some cases the first digit indicates the length of the IIN or the
					 responsibility of its assignment outside of ISO.
					If MII = 9 then the first 3 digits should be the country code (CC).

		IAI: Individual Account Identification. Up to 12 digits:

			Assigned by the card issuing institution.

		CD: Check Digit. 1 digit:

			Calculated using the Luhn formula for computing modulus 10
			 "double-add-double" check digit: Double the value of alternate (odd)
			 digits starting by the least significant (first right hand) digit.
			Then add the individual digits of doubled (odd) numbers and even digits
			 of the original number.
			If the value ends in 0 then the check digit is 0.
			Otherwise subtract the value from the next higher number ending in 0
			 (tens complement of the unit digit).
			The result is the check digit.
			Example: If the account number without check digit is 1234 5678 9012 344
			 then (8) + 4 + (6) + 2 + (2) + 0 + (1 + 8) + 8 + (1 + 4) + 6 + (1 + 0)
			 + 4 + (6) + 2 + (2) = 65, therefore the check digit is 70 - 65 = 5 and
			 so the complete account number is 1234 5678 9012 3445.

		MasterCard PAN is variable up to 16 digits and VISA is 13 or 16 digits, including check digit.
		If track 3 is to be used together with track 2 then PAN is an optional field.

	FS: Field Separator. 1 character: =.

	CC: Country Code. 3 digits:

		Country codes are defined in ISO 3166: 724 for Spain, 840 for USA, etc.
		If this field in not used a FS will be in place.

	CuC: Currency Code. 3 digits:

		Currency codes are defined in ISO-4217:724 for Spanish peseta, 840 for US dollar, etc.
		If 3 zeros (000) are written in this field it means card not valid for international interchange.

	CE: Currency Exponent. 1 digit:

		0-5: Power of ten by which multiply the currency amount fields (AA and AR)
		 to get their actual values in the currency of the CuC field.

	AA: Amount Authorized per cycle. 4 digits:

		Maximum amount of money permitted in one cycle.
		If 4 zeros (0000) are written in this field it means card not valid for
		 charge operations (no debit).

	AR: Amount Remaining this cycle. 4 digits:

		Maximum amount of money permitted in this cycle.
		This field is dynamic, it is initialized with the value of the AA field the
		 first time the card is used in a new cycle.
		Then it is modified accordingly.

	CB: Cycle Begin (Validity Date). 4 digits:

		Date in which actual cycle began.
		The format is YDDD where Y stands for the least significant digit of the year
		 and DDD is the day of the year (001 to 366).
		The field must be updated each time a new cycle begin.

		Alternatively this field may indicate the date from which the card is valid.

	CL: Cycle Length. 2 digits:

		00: Infinite, AR should be decremented but never reset.
		01-79: Number of days.
		80: Cycle begin each 7 days.
		81: Cycle begin each 14 days.
		82: Cycle begins each 1st and 15th days of every month.
		83: Cycle begins the day of the month specified in CB of every month.
		84: Cycle begins the day of the month specified in CB of every third month.
		85: Cycle begins the day of the month specified in CB of every sixth month.
		86: Cycle begins the day of the year specified in CB of every year.
		87-89: Reserved for future use by ISO/TC 68.
		90-99: Reserved for proprietary use of card issuer, but not for international interchange.

		This field represents the duration of the cycle for which the AA limit holds.

	RC: Retry Count. 1 digit:

		Number of remaining PIN trials. It is initialized to 3 and reduced by one unit after every wrong PIN entered. It is reset to 3 after a successful PIN introduction. When this field reaches 0 the card is invalid for any interchange purpose.

	PINCP: PIN Control Parameters (PINPARM). 6 digits:

		If FC = 01 the two first digits represent the algorithm used to calculate PIN, where 00-09 mean private algorithm, 10-19 mean DEA and values 20 to 99 are reserved for future use by ISO/TC 68. Next 4 digits are PIN offset, a complementary value of PIN so customers can change their PIN, or PVV.

		If FC = 02 the first digit represents the algorithm used to calculate PIN, where 0 means private algorithm, 1 means DEA and values 2 to 9 are reserved for future use by ISO/TC 68. The second digit represents a key for the algorithm. Next 4 digits are PIN offset, a complementary value of PIN so customers can change their PIN, or PVV.

		If this field is not used a FS will be in place.

	IC: Interchange Control. 1 digit:

		0: No restriction.
		1: Not available for international interchange.
		2-8: Limited interchange, only local use and under agreement.
		9: Limited interchange, recommended for test cards.

	PANSR: PAN Service Restriction. 2 digits:

		The first digit defines the type of account:

			0: Associated account number not encoded on track.
			1: Savings account.
			2: Current or checking account.
			3: Credit card account.
			4: Generic or universal account.
			5: Interest-bearing current or checking account.
			6-8: Reserved for future use by ISO/TC 68.
			9: Reserved for card issuer's internal use, not for interchange.

		The second digit defines the service restrictions:

			0: No restrictions.
			1: No cash dispense.
			2: No point of sale (POS) transaction.
			3: No cash dispense and no POS transaction.
			4: Authorization required.
			5-7: Reserved for future use by ISO/TC 68.
			8-9: Reserved for card issuer's internal use, only local use and under agreement.

	FSANSR: FSAN Service Restriction. 2 digits:

		Same values and meaning as for PANSR field.

	SSANSR: SSAN Service Restriction. 2 digits:

		Same values and meaning as for PANSR field.

	ED: Expiry Date. 4 digits: YYMM.

		If this field is not used a FS will be in place.

	CSN: Card Sequence Number. 1 digit:

		Allows to distinguish among different cards with the same PAN. It is incremented by one unit in any additional card.

		If FC = 02 and a FS is in place it means that field ACSN is present.

	CScN: Card Security Number. 9 digits:

		The first digit represents the algorithm used to calculate a verification value to validate the information on the magnetic track against the embossed characters, where 0-4 are available for national use, 5-8 are available for international security methods given by ISO/TC 68, and 9 is reserved for private use. Next 8 digits are the verification value.

		If this field in not used a FS will be in place.

	FSAN: First Subsidiary Account Number. Variable number of digits:

		This is an optional field.

	FS: Field Separator. 1 character: =.

	SSAN: Second Subsidiary Account Number. Variable number of digits:

		This is an optional field.

	FS: Field Separator. 1 character: =.

	RM: Relay Marker. 1 digit:

		0: Include AD and DD fields in transactions messages.
		1: Do not include AD field in transactions messages.
		2: Do not include DD field in transactions messages.
		3-9: Invalid.

	CCD: Crypto Check Digits. 6 digits:

		A validation value which permits integrity verification of the magnetic stripe content.

		If this field in not used a FS will be in place.

	AD: Additional Data. Rest of characters:

		Optional field reserved for proprietary use of card issuer if FC = 01. 

		If FC = 02 the following subfields are required:

	TD: Transaction Date. 4 digits:

		Date of last cash dispense. The format is YDDD where Y stands for the least significant digit of the year and DDD is the day of the year (001 to 366).

		If this field in not used a FS will be in place.

	AVV: Additional Verification Value(s). 8 digits:

		Validation of the PIN or two additional PINs corresponding to different keys of the same algorithm. It can be an eight digit value, two four digit numbers or, in connection with the last four digits of the PINCP field, two six digit numbers.

		If this field in not used a FS will be in place.

	ACSN: Alternative Card Sequence Number. 3 digits:

		Same purpose as CSN field but it allows for a maximum of 1000 different cards instead of 10.

		If this field in not used a FS will be in place.

	INIC: International Network Identification Code. 3 digits:

		Code for identification of an international group of issuers, when the IIN can not be used. It is equivalent to the term Network International Identifier used in ISO 8583.

		If this field in not used a FS will be in place.

	DD: Discretionary Data. Rest of characters:

		Optional field reserved for proprietary use of card issuer.

	ES: End Sentinel. 1 character: ?.

	LRC: Longitude Redundancy Check. 1 character.
*/

/*	Caja de Madrid ATM card (VISA logo):

Embossing:
	Card holder : L. PADILLA
	Card number*: 1234 5678 9012 3445
	Expiration  : 01/99

*The card number (PAN) uses, as most of the credit and debit cards, the Luhn Check Digit Algorithm. Valid numbers must comply with the following rule. If the card number has an even number of digits, then the adding up of the even numbered digits plus the odd numbered digits doubled (minus 9 if the doubled digit is greater than 9) has to be multiple of 10. If the card number has an odd number of digits, then the same applies but doubling even (instead of odd) numbered digits. Using the example above:
2 x 1 + 2 + 2 x 3 + 4 + 2 x 5 - 9 + 6 + 2 x 7 - 9 + 8 + 2 x 9 - 9 + 0 + 2 x 1 + 2 + 2 x 3 + 4 + 2 x 4 + 5 = 70 and therefore the number in the example is a valid number for a credit or debit card.
Actually is the other way round, the last digit of the card number is calculated so that the whole number complies with Luhn Check, therefore the last digit is called check digit.

Track 1:

	%B1234567890123445^PADILLA/L.                ^99011200000000000000**XXX******?*
	^^^               ^^                         ^^   ^       ^         ^        ^^
	|||_ Card number  ||_ Card holder            ||   |       |         |_ CVV** ||_ LRC
	||_ Format code   |_ Field separator         ||   |       |                  |_ End sentinel
	|_ Start sentinel           Field separator _||   |       |_ Discretionary data
	                                  Expiration _|   |_ Service code

Track 2:

	;1234567890123445=99011200XXXX00000000?*
	^^               ^^   ^   ^           ^^
	||_ Card number  ||   |   |_ Encrypted||_ LRC
	|_ Start sentinel||   |      PIN***   |_ End sentinel
	                 ||   |_ Service code
	Field separator _||_ Expiration

Track 3:

	;011234567890123445=724724100000000000030300XXXX040400099010=************************==1=0000000000000000?*
	^^ ^               ^^  ^  ^            ^ ^  ^   ^^ ^   ^    ^^                       ^^^^^               ^^
	|| |               ||  |  |_ Currency  | |  |   || |   |    ||_ First subsidiary     |||||_ Additional   ||
	|| |               ||  |     exponent  | |  |   || |   |    |   account number (FSAN)||||   data         ||
	|| |_ Card number  ||  |_ Currency     | |  |   || |   |    |_ Field separator       ||||_ Field         ||_ LRC
	||_ Format code    ||     (Peseta)     | |  |   || |   |_ Expiration                 |||   separator     |_ End sentinel
	|_ Start sentinel  ||_ Country (Spain) | |  |   || |_ FSAN service restriction       |||_ Relay marker
	                   |_ Field separator  | |  |   ||_ PAN service restriction          ||_ Field separator
	                         Cycle length _| |  |   |_ Interchange control               |_ Field separator
	                            Retry count _|  |_ Encrypted PIN***


**The CVV (Card Verification Value) is a cryptographic signature of the card number, the expiration date and the service code to verify the integrity of these data in the track. It is calculated with an algorithm similar to that of PIN encryption.

***The PIN (Personal Identification Number) is basically encrypted as follows. The card number is taken as an hexadecimal number and is encrypted with the DES algorithm using a secret key, which is called the "PIN key". The first four digits are decimalized (i.e., A = 0, B = 1, ...) and are called the "natural PIN". An offset is added (without carry) to the natural PIN in order to obtain the customer PIN. The customer PIN may be changed but the natural PIN cannot. The offset is what is written in track 3 and I called the "encrypted PIN". Here you have an example:
Card number: 1234567890123445hex input for DES.
PIN key: 0123456789ABCDEFhex key for DES.
Encrypted card number: 9A466AD30DFE0381hex output from DES.
Natural PIN: 9046.
Offset: 2298 (this number is written on track 3).
Customer PIN: 1234.
See also the original VISA scheme and a discussion on other systems. See the two much more detailed and complete documents linked in my main page for magnetic stripe cards.
*/
/*	Caja Madrid VISA or VISA Electron card:

Embossing or printing:
	Card holder: L. PADILLA
	Card number: 1234 5678 9012 3445
	Expiration : 01/99

Track 1:

	%B1234567890123445^PADILLA/L.                ^99011X100000*000000000XXX000000?*
	^^^               ^^                         ^^   ^       ^         ^        ^^
	|||_ Card number  ||_ Card holder            ||   |       |         |_ CVV   ||_ LRC
	||_ Format code   |_ Field separator         ||   |       |                  |_ End sentinel
	|_ Start sentinel           Field separator _||   |       |_ Discretionary data
	                                  Expiration _|   |_ Service code: 101 for VISA and 121 for VISA Electron

Track 2:

	;1234567890123445=99011X10XXXXXXX00000?*
	^^               ^^   ^   ^   ^       ^^
	||_ Card number  ||   |   |   |_ CVV  ||_ LRC
	|_ Start sentinel||   |   |           |_ End sentinel
	Field separator _||   |   |_ Encrypted PIN (except if duplicate card)
	      Expiration _|   |_ Service code: 101 for VISA and 121 for VISA Electron

Track 3:

	;011234567890123445=724724000000000****00300XXXX020200099010=********************==1=100000000000000000**?*
	^^ ^               ^^  ^           ^     ^  ^   ^^ ^   ^    ^^                   ^^^^^                   ^^
	|| |               ||  |_ Currency |     |  |   || |   |    ||_ FSAN             |||||                   ||
	|| |_ Card number  ||     (Peseta) |     |  |   || |   |    |_ Field separator   |||||_ Additional data  ||_ LRC
	||_ Format code    ||_ Country     |     |  |   || |   |_ Expiration             ||||_ Field separator   |_ End sentinel
	|_ Start sentinel  |   (Spain)     |     |  |   || |_ FSAN service restriction   |||_ Relay marker
	                   |_ Field        |     |  |   ||_ PAN service restriction      ||_ Field separator
	                      separator    |     |  |   |_ Interchange control           |_ Field separator
	                    Validity date _|     |  |_ Encrypted PIN (except if duplicate card)
	              (except if duplicate card) |_ Retry count
*/
/*	Uno-e VISA Electron card:

Printing:
	Card holder: L. PADILLA
	Card number: 1234 5678 9012 3445
	Expiration : 01/99

Track 1:

	%B1234567890123445^PADILLA/L.                ^99011211XXXX*000000**0XXX0**000?*
	^^^               ^^                         ^^   ^  ^^   ^         ^        ^^
	|||_ Card number  ||_ Card holder            ||   |  ||   |_ Discr. |_ CVV   ||_ LRC
	||_ Format code   |_ Field separator         ||   |  ||      data            |_ End sentinel
	|_ Start sentinel           Field separator _||   |  ||_ PVV*
	                                  Expiration _|   |  |_ PVV key indicator
	                                                  |_ Service code

Track 2:

	;1234567890123445=99011211XXXXXXX00***?*
	^^               ^^   ^  ^^   ^       ^^
	||_ Card number  ||   |  ||   |_ CVV  ||_ LRC
	|_ Start sentinel||   |  ||_ PVV*     |_ End sentinel
	Field separator _||   |  |_ PVV key indicator
	      Expiration _|   |_ Service code

Track 3:

	;011234567890123445=000978100000000****8330*0000920000099010=************************==1=0000000*00000000?*
	^^ ^               ^   ^  ^        ^   ^ ^      ^^     ^    ^^                       ^^^^^               ^^
	|| |               |   |  |_ Curr. |   | |_Retry||     |    ||_ FSAN                 |||||_ Additional   ||_ LRC
	|| |_ Card number  | Curr.   expon.|   |   count||     |    |_ Field separator       ||||   data         |_ End sentinel
	||_ Format code    | (Euro)        |   |        ||     |_ Expiration                 ||||_ Field separator
	|_ Start sentinel  |_ Field        |   |_ Cycle ||_ PAN service restriction          |||_ Relay marker
	                      separator    |      length|_ Interchange control               ||_ Field separator
	                    Validity date _|                                                 |_ Field separator

*The PVV (PIN Verification Value) is another way of PIN encryption. It is calculated with an algorithm similar to that described above.
*/
/*	Caja Bilbao Vizcaya ATM card (MasterCard logo):

Embossing:
	Card holder: L. PADILLA
	Card number: 1234 5678 9012 3445
	Expiration : 01/99

Track 1:

	%B1234567890123445^PADILLA/L.                ^990110100000000XXX****XXX******?*
	^^^               ^^                         ^^   ^       ^  ^      ^        ^^
	|||_ Card number  ||_ Card holder            ||   |       |  |      |_ CVV   ||_ LRC
	||_ Format code   |_ Field separator         ||   |       |  |_ Number       |_ End sentinel
	|_ Start sentinel           Field separator _||   |       |_ Discretionary data
	                                  Expiration _|   |_ Service code

Track 2:

	;1234567890123445=990110100000XXXXXX00?*
	^^               ^^   ^       ^  ^    ^^
	||_ Card number  ||   |  CVV _|  |    ||_ LRC
	|_ Start sentinel||   |  Number _|    |_ End sentinel
	                 ||   |_ Service code
	Field separator _||_ Expiration

Track 3:

	;011234567890123445=7247241000000000000001000000040400099010=************************==0=0002000000******?*
	^^ ^               ^^  ^  ^              ^      ^^ ^   ^    ^^                       ^^^^^               ^^
	|| |_ Card number  ||  |  |_ Currency    |      || |   |    ||_ First subsidiary     |||||_ Additional   ||
	||_ Format code    ||  |     exponent    |      || |   |    |   account number (FSAN)||||   data         ||
	|_ Start sentinel  ||  |_ Currency       |      || |   |    |_ Field separator       ||||_ Field         ||_ LRC
	  Field separator _||     (Peseta)       |      || |   |_ Expiration                 |||   separator     |_ End sentinel
	                    |_ Country (Spain)   |      || |_ FSAN service restriction       |||_ Relay marker
	                            Retry count _|      ||_ PAN service restriction          ||_ Field separator
	                                                |_ Interchange control               |_ Field separator
*/
/*	Sanitas (private sanitary coverage) card:

Embossing:
	Card holder: L. PADILLA
	Card number: 999999 8888 777 666 5
	Validity   : 01/98 - 02/99

Track 1:

	%BXXXXXX99999900000888877=L. PADILLA                    =666599029801?*
	^^^     ^          ^     ^^                             ^^   ^       ^^
	|||     |          |     ||_ Card holder                ||   |       ||_ LRC
	|||     |          |     |_ Field separator             ||   |       |_ End sentinel
	|||     |          |_ Card number(2)                    ||   |_ Validity
	|||     |_ Card number(1)              Field separator _||_ Card number(3)
	|||_ Number
	||_ Format code
	|_ Start sentinel

Track 2:

	;XXXXXX999999000008888777=666990259801?*
	^^     ^          ^      ^^  ^   ^^   ^^
	||     |          |      ||  |   ||   ||_ LRC
	||     |          |      ||  |   ||   |_ End sentinel
	||     |          |      ||  |   ||_ Validity(2)
	||     |          |      ||  |   |_ Card number(4)
	||     |          |      ||  |_ Validity(1)
	||     |          |      ||_ Card number(3)
	||     |          |      |_ Field separator
	||     |          |_ Card number(2)
	||     |_ Card number(1)
	||_ Number
	|_ Start sentinel

Track 3:

	Empty (all zeros)
*/
/*	Social security card:

Embossing:
	Card holder: L. PADILLA
	Card number: 999999 PDVS123456789012
	Expiration : 03/99

Track 1:

	%B999999^PDVS123456789012^PADILLA L.                    ^0X0000399           ?*
	^^^     ^^^^^^           ^^                             ^ ^   ^              ^^
	|||     ||||||_ Card     ||_ Card holder                | |   |_ Expiration  ||_ LRC
	|||     |||||   number(2)|_ Field separator (formerly =)| |                  |_ End sentinel
	|||     |||||_ 3rd letter from 2nd surname              | |_ = 1 -> Non pensioner
	|||     ||||_ 1st letter from 2nd surname               |    = 2 -> Pensioner
	|||     |||_ 3rd letter from 1st surname                |_ Field separator (formerly =)
	|||     ||_ 1st letter from 1st surname
	|||     |_ Field separator (formerly =)
	|||_ Card number(1)
	||_ Format code
	|_ Start sentinel

Track 2:

	;999999554749123456789012=00X990300000?*
	^^     ^  ^  ^           ^  ^^        ^^
	||     |  |  |_ Card     |  ||        ||_ LRC
	||     |  |     number(2)|  ||        |_ End sentinel
	||     |  |              |  ||_ Expiration
	||     |  |              |  |_ See above
	||     |  |              |_ Field separator
	||     |  |_ = 30 x (#V - 30) + #S - 22, where #X means decimal value of character X in the ALPHA format (#A = 33, #B = 34, ...)
	||     |_ = 30 x (#P - 30) + #D - 22, where P, D, V and S come from the card number (see above)
	||_ Card number(1)
	|_ Start sentinel

Track 3:

	Empty (all zeros) or not present
*/
/*	Vitalicio-Salud (private sanitary coverage) card:

Embossing:
	Card holder: L. PADILLA
	Card number: 0123456789
	Validity   : 04/99 - 12/99

Track 1:

	%0123456789L. PADILLA                ?*
	^^         ^                         ^^
	||         |_ Card holder            ||_ LRC
	||_ Card number                      |_ End sentinel
	|_ Start sentinel

Track 2:

	;0123456789?*
	^^         ^^
	||_ Card   ||_ LRC
	|   number |_ End sentinel
	|_ Start sentinel

Track 3:

	Empty (all zeros)
*/
/*	Ciudad de las Artes y las Ciencias pass ticket:

Printing:

	Date: 16/12/00 20:00
	Number: 010100381781

Track 1:

	Not present

Track 2:

	;012001120100381781?*
	^ ^       ^        ^^
	| |_ Date?|        ||_ LRC
	|         |        |_ End sentinel
	|         |_ Partial number
	|_ Start sentinel

Track 3:

	Not present
*/
/*	Graphispag93 exhibitor ID card:

Printing:

	Card holder: RUEDA, J

Track 1:

	%RUEDA, J?*
	^^       ^^
	||       ||_ LRC
	||       |_ End sentinel
	||_ Card holder
	|_ Start sentinel

Track 2:

	Not present

Track 3:

	Not present
*/
/*	Carrefour gas station discount ticket:

Printing:

	None

Track 1:

	Not present

Track 2:

	;9999989999999999=01015990000000000000?*
	^                ^                    ^^
	|_ Start sentinel|_ Field separator   ||_ LRC
	                                      |_ End sentinel

Track 3:

	Not present
*/
/*	Madrid public parking ticket:

Printing:

	Date: 14:31 06-02-98

Track 1:

	Not present

Track 2:

	;11431060298?*
	^ ^         ^^
	| |_ Date   ||_ LRC
	|_ Start    |_ End sentinel
	   sentinel

Track 3:

	Not present
*/
/*	Parque Ferial Juan Carlos I parking ticket:

Printing:

	Date: 27/02/2003 13:32:05
	String: 01044 9 35397 P01

Track 1:

	Not present

Track 2:

	;304601=0534177205044000000000000100?*
	^      ^  ********^                 ^^
	|      |          |_ Digits 3 to 5  ||
	|      |             of string      ||
	|      |_ Field separator           ||_ LRC
	|_ Start sentinel                   |_ End sentinel

Track 3:

	Not present
*/
/*	Val Thorens parking card:

Printing:
	Number  : 11069
	Parking : P0
	Validity: 02/01/96 - 06/01/96

Track 1:

	Not present

Track 2:

	;>4155594>4713000110=11106909912310000?*
	^                   ^ ^               ^^
	|_ Start sentinel   | |_ Number       ||_ LRC
	                    |_ Field separator|_ End sentinel

Track 3:

	Not present
*/
/*	Read more at: http://www.epanorama.net/documents/smartcard/magcard.html
*/

#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_MODE_2					0x33
//#define	MMD1100_DEFINE_TRACK_DATA_MODE						0x35
//#define	MMD1100_DEFINE_TRACK_DATA_MODE						0x37

#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_MODE_2 )
			{
				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_MODE_2)
	{	/* 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;
}