package kr.co.icontrols.ilp300_700.fingerprint;


import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
//import android.support.annotation.Nullable;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import kr.co.icontrols.ilp300_700.global.Declare.PrivateBR;
import kr.co.icontrols.ilp300_700.global.Declare.FPReaderPacket;
import android_serialport_api.SerialPort;

public class FingerprintScanService extends Service {

    String TAG = "FingerprintScanService";

    protected InputStream mInputStream;
    protected static OutputStream mOutputStream;
    private SerialPort mSerialPort = null;
    private SerialDataReceiver mSerialDataReceiver;
    private FingerprintScanThread mFingerprintScanThread;

    private final String SERIALPORTINFO = "COM4_ttyS4_Baudrate_57600";
    int SERIAL_RECEIVE_TIMEOUT = 1000;   // Packet receiving duration from start to end
    int SERIAL_PACKET_EXPECTED_LENGTH = 12;   // Fingerprint date packet length
    int SERIAL_PACKET_FIXEDBASE_LENGTH = 9;   // Base fingerprint date packet length (STX(2Bytes), ID(4Bytes), PID(1Byte), Length(2Bytes), total 9Bytes)
    int SERIAL_PACKET_MAX_LENGTH = 512;   // MAX data packet length
    byte[] hRcvData = new byte[SERIAL_PACKET_MAX_LENGTH];

    enum SCANSTATUS {
        IDLE,   // Idle
        REQ_GETIMAGE,   // getimage 요청
        ACK_GETIMAGE,   // getimage 성공
        NACK_GETIMAGE,   // getimage 실패
        REQ_GENCHAR,   // genchar 요청
        ACK_GENCHAR,   // genchat 성공
        NACK_GENCHAR,   // genchar 실패
        REQ_UPCHAR,   // upchar 요청
        ACK_UPCHAR,   // upchar 성공
        NACK_UPCHAR,   // upchar 실패
        READY_RCVCHAR,   // 지문데이터 수신
    }
    protected SCANSTATUS eSCANSTATUS = SCANSTATUS.IDLE;

    final int HANDLEMEG_SND_GETIMAGE = 100;
    final int HANDLEMEG_SND_GENCHAR = 200;
    final int HANDLEMEG_SND_UPCHAR = 300;
    final int HANDLEMEG_RCV_MSG = 400;


    @Override
    public void onCreate() {
        super.onCreate();
        try {
            if (startSerialPort()) {
                Log.i(TAG, "[onCreate] Fingerprint serial port opened!!");
                sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
            }
            else Log.e(TAG, "[onCreate] Fingerprint serial port NOT opened!!");
        } catch (Exception e) {
            Log.e(TAG, "[Exception] onCreate()");
            e.printStackTrace();
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "[onStartCommand] flags [" + flags + "], startId [" + startId + "]");
        return START_STICKY;
    }

   // @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void setScanStatus(SCANSTATUS eStatus) {
        try {
            eSCANSTATUS = eStatus;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setScanStatus(SCANSTATUS eStatus)");
            e.printStackTrace();
        }
    }

    private SCANSTATUS getScanStatus() {
        try {
            return eSCANSTATUS;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] getScanStatus()");
            e.printStackTrace();
            return null;
        }
    }

    public boolean startSerialPort() {
        try {
            Log.i(TAG, "[startSerialPort] ===== START =====");

            mSerialPort = openSerialPort(SERIALPORTINFO);
            Log.i(TAG, "[startSerialPort] Open FD : " + mSerialPort.get_FD());

            if (mSerialPort == null) {
                Log.e(TAG, "[startSerialPort] mSerialPort is null!!");
                return false;
            }

            Log.i(TAG, "[startSerialPort] ReceiveSerialDataThread Create : " + mSerialPort.toString());
            mOutputStream = mSerialPort.getOutputStream();
            mInputStream = mSerialPort.getInputStream();
            mSerialDataReceiver = new SerialDataReceiver(FPScanHandler);
            mSerialDataReceiver.start();
            mFingerprintScanThread = new FingerprintScanThread(FPScanHandler);
            mFingerprintScanThread.start();
            return true;

        } catch (Exception e) {
            Log.e(TAG, "[Exception] startSerialPort()");
            e.printStackTrace();
            return false;
        }
    }

    public SerialPort openSerialPort(String strSerialInfo) throws SecurityException, IOException, InvalidParameterException {
        try {
            Log.i(TAG, "[openSerialPort] ===== START =====");
            if (mSerialPort == null) {
                // Read serial port parameters
                String[] aSerialInfo = strSerialInfo.split("_");
                int nBaudrate = Integer.parseInt(aSerialInfo[3], 10);
                String strPath = "/dev/" + aSerialInfo[1];
                Log.i(TAG, "[openSerialPort] nBaudrate [" + nBaudrate + "], strPath [" + strPath + "]");

                // Check parameters
                if ((strPath.length() < 0) || (nBaudrate < 0)) {
                    throw new InvalidParameterException();
                }

                Log.i(TAG, "[openSerialPort] Serialport will be open though " + aSerialInfo[0]);
                mSerialPort = new SerialPort(new File(strPath), nBaudrate, 0);
                Log.i(TAG, "[openSerialPort] " + aSerialInfo[0] + " opened!");
                Log.i(TAG, "[openSerialPort] mSerialPort : " + mSerialPort);
                Log.i(TAG, "[openSerialPort] mSerialPort FD : " + mSerialPort.get_FD());
            }
            return mSerialPort;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] openSerialPort(SerialInfo)");
            e.printStackTrace();
            return null;
        }
    }

    public boolean sendPacketMsg(byte[] hData) {
        try {
//            Log.i(TAG, "[sendPacketMsg] hData = " + Global.printHexs(hData));
            mOutputStream.write(hData);
            mOutputStream.flush();
            return true;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] sendPacketMsg(hData)");
            e.printStackTrace();
            return false;
        }
    }

    private void receivedMsg(byte[] hRcvData, int nDataLength) {
        try {
            byte[] hData = new byte[nDataLength];
            System.arraycopy(hRcvData, 0, hData, 0, nDataLength);
//            Log.e(TAG, "[receivedMsg] hData : " + Global.printHexs(hData));
            sendHandlerMsg(FPScanHandler, HANDLEMEG_RCV_MSG, hData);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] receivedMsg(byte[] hRcvData, int nDataLength)");
            e.printStackTrace();
        }
    }

    private byte[] makeGetimageMsg() {
        try {
            byte[] hMsg = new byte[4];
            hMsg[0] = FPReaderPacket.PID_TYPE_INST;   // packet flag (packet type)
            short sPacketlength = (short) ((hMsg.length - 3) + 2);   // 2 is checksum length (The check is 2Bytes)
//            Log.d(TAG, "[makeGetimageMsg] sPacketlength = " + Global.ShorttoString(sPacketlength));
            hMsg[1] = (byte) (sPacketlength >> 8);   // length high
            hMsg[2] = (byte) sPacketlength;   // length low
            hMsg[3] = FPReaderPacket.CMD_GETIMAGE;   // instruction code (cmd)
            return makePacketMsg(hMsg);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeGetimageMsg()");
            e.printStackTrace();
            return null;
        }
    }

    private byte[] makeGencharMsg() {
        try {
            byte[] hMsg = new byte[5];
            hMsg[0] = FPReaderPacket.PID_TYPE_INST;
            short sPacketlength = (short) ((hMsg.length - 3) + 2);   // 2 is checksum length (The check is 2Bytes)
//            Log.d(TAG, "[makeGencharMsg] sPacketlength = " + Global.ShorttoString(sPacketlength));
            hMsg[1] = (byte) (sPacketlength >> 8);   // length high
            hMsg[2] = (byte) sPacketlength;   // length low
            hMsg[3] = FPReaderPacket.CMD_GENCHAR;
            hMsg[4] = (byte) 0x01;   // Fingerprint saving buffer index (fixed as 0x01)
            return makePacketMsg(hMsg);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeGencharMsg()");
            e.printStackTrace();
            return null;
        }
    }

    private byte[] makeUpcharMsg() {
        try {
            byte[] hMsg = new byte[5];
            hMsg[0] = FPReaderPacket.PID_TYPE_INST;
            short sPacketlength = (short) ((hMsg.length - 3) + 2);   // 2 is checksum length (The check is 2Bytes)
//            Log.d(TAG, "[makeUpcharMsg] sPacketlength = " + Global.ShorttoString(sPacketlength));
            hMsg[1] = (byte) (sPacketlength >> 8);   // length high
            hMsg[2] = (byte) sPacketlength;   // length low
            hMsg[3] = FPReaderPacket.CMD_UPCHAR;
            hMsg[4] = (byte) 0x01;   // Fingerprint saving buffer index (fixed as 0x01)
            return makePacketMsg(hMsg);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeUpcharMsg()");
            e.printStackTrace();
            return null;
        }
    }

    private byte[] makePacketMsg(byte[] hMsg) {
        try {
//            Log.v(TAG, "[makePacketMsg] hMsg [" + Global.printHexs(hMsg) + "]");
            short sCS = makeChecksum(hMsg);
            byte[] hPacket = new byte[hMsg.length + 8];
            hPacket[0] = FPReaderPacket.STX[0];
            hPacket[1] = FPReaderPacket.STX[1];
            hPacket[2] = FPReaderPacket.ID_READER[0];
            hPacket[3] = FPReaderPacket.ID_READER[1];
            hPacket[4] = FPReaderPacket.ID_READER[2];
            hPacket[5] = FPReaderPacket.ID_READER[3];
            for (int i = 0; i < hMsg.length; i++) {
                hPacket[6 + i] = hMsg[i];
            }
            hPacket[hPacket.length - 2] = (byte) (sCS >> 8);   // checksum high
            hPacket[hPacket.length - 1] = (byte) sCS;   // checksum low
//            Log.v(TAG, "[makePacketMsg] hPacket [" + Global.printHexs(hPacket) + "]");
            return hPacket;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makePacketMsg(byte[] hMsg)");
            e.printStackTrace();
            return null;
        }
    }

    public short makeChecksum(byte[] hData) {
        try {
            short sCS = 0x00;

            for (int i = 0; i < hData.length; i++) {
                sCS += hData[i];
            }
//            Log.d(TAG, "[makeChecksum] sCS = " + Global.ShorttoString(sCS));
            return sCS;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeChecksum(hData)");
            e.printStackTrace();
            return (byte) 0xFF;
        }
    }

    protected boolean bFingerprintBlock = false;
    private void setFingerprintScanBlock(boolean bBlock) {
        try {
            bFingerprintBlock = bBlock;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setFingerprintScanBlock(boolean bBlock)");
            e.printStackTrace();
        }
    }

    private boolean getFingerprintScanBlock() {
        try {
            return bFingerprintBlock;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] getFingerprintScanBlock()");
            e.printStackTrace();
            return false;
        }
    }

    public void decodeRcvMsg(byte[] RcvMsg) {
        try {
            SCANSTATUS eStatus = getScanStatus();
//            Log.i(TAG, "[decodeRcvMsg] eStatus [" + eStatus + "], RcvMsg : " + Global.printHexs(RcvMsg));

            byte hPID = RcvMsg[6];
            byte hCFCode = RcvMsg[9];

            if (hPID == FPReaderPacket.PID_TYPE_ACK) {
                if (hCFCode == FPReaderPacket.CFCODE_OK) {
                    if (eStatus == SCANSTATUS.REQ_GETIMAGE) {
                        sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GENCHAR, null);
                    }
                    else if (eStatus == SCANSTATUS.REQ_GENCHAR) {
                        if (getFingerprintScanBlock()) sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
                        else sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_UPCHAR, null);
                    }
                    else if (eStatus == SCANSTATUS.REQ_UPCHAR) {
                        setScanStatus(SCANSTATUS.READY_RCVCHAR);
                    }
                    else {
                        Log.w(TAG, "[decodeRcvMsg] Not supported eStatus -> " + eStatus);
                        setFingerprintScanBlock(false);
                        sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
                    }
                }
                else {
                    if (hCFCode != FPReaderPacket.CFCODE_NOFPONSENSOR) {
                        Log.w(TAG, "[decodeRcvMsg] hCFCode is not OK -> " + String.format("%02X", hCFCode));
                    }
                    setFingerprintScanBlock(false);
                    sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
                }
            }
            else if (hPID == FPReaderPacket.PID_TYPE_LASTDATA) {
                if (eStatus == SCANSTATUS.READY_RCVCHAR) {
                    setFingerprintScanBlock(true);
//                    Log.i(TAG, "[decodeRcvMsg] RcvMsg : " + Global.printHexs(RcvMsg));
                    sendFingerprintBR(RcvMsg);
                    sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
                }
                else {
                    Log.w(TAG, "[decodeRcvMsg] Not supported eStatus -> " + eStatus);
//                    sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
                }
            }
            else {
                Log.w(TAG, "[decodeRcvMsg] hPID is not OK -> " + String.format("%02X", hPID));
                sendHandlerMsg(FPScanHandler, HANDLEMEG_SND_GETIMAGE, null);
            }

        } catch (Exception e) {
            Log.e(TAG, "[Exception] decodeRcvMsg(byte[] RcvMsg)");
            e.printStackTrace();
        }
    }

    private void sendFingerprintBR(byte[] hData) {
        try {
            Intent mIntent = new Intent();
            mIntent.setAction(PrivateBR.FINGERPRINT_DETECTED);
            mIntent.putExtra(PrivateBR.FINGERPRINT_DATA, hData);
            getApplicationContext().sendBroadcast(mIntent);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] sendFingerprintBR(byte[] hData)");
            e.printStackTrace();
        }
    }

    private void sendHandlerMsg(Handler Handle, int nStatus, Object Msg) {
        try {
//            Log.i(TAG, "[sendHandlerMSG] nStatus [" + nStatus + "]");
            Message mMessage = Handle.obtainMessage();
            mMessage.what = nStatus;
            mMessage.obj = Msg;

            Handle.sendMessage(mMessage);

        } catch (Exception e) {
            Log.e(TAG, "[Exception] sendHandlerMsg(Handler Handle, int nStatus, Object Msg)");
            e.printStackTrace();
        }
    }

    private void sendHandlerMsgDelay(Handler Handle, int nStatus, Object Msg, int nDelay) {
        try {
            Log.i(TAG, "[sendHandlerMsgDelay] nStatus [" + nStatus + "]");
            Message mMessage = Handle.obtainMessage();
            mMessage.what = nStatus;
            mMessage.obj = Msg;

            Handle.sendMessageDelayed(mMessage, nDelay);

        } catch (Exception e) {
            Log.e(TAG, "[Exception] sendHandlerMsgDelay(Handler Handle, int nStatus, Object Msg, int nDelay)");
            e.printStackTrace();
        }
    }

    public Handler FPScanHandler = new Handler(Looper.getMainLooper()) {
        public void handleMessage(Message msg) {
//            if (!Global.getEnableDeviceInput()) {
//                Log.w(TAG, "[FPScanHandler] Global.getEnableDeviceInput() = " + Global.getEnableDeviceInput());
//                return;
//            }
//            Log.d(TAG, "FPScanHandler : " + msg.what);

            switch (msg.what) {
                case HANDLEMEG_SND_GETIMAGE:
                    setScanStatus(SCANSTATUS.REQ_GETIMAGE);
                    sendPacketMsg(makeGetimageMsg());
                    break;

                case HANDLEMEG_SND_GENCHAR:
                    setScanStatus(SCANSTATUS.REQ_GENCHAR);
                    sendPacketMsg(makeGencharMsg());
                    break;

                case HANDLEMEG_SND_UPCHAR:
                    setScanStatus(SCANSTATUS.REQ_UPCHAR);
                    sendPacketMsg(makeUpcharMsg());
                    break;

                case HANDLEMEG_RCV_MSG:
                    decodeRcvMsg((byte[]) msg.obj);
                    break;

                default:
                    break;
            }

        }
    };

    public class FingerprintScanThread extends Thread {
        Handler FPReaderMgrHandler;

        public FingerprintScanThread(Handler Handle) {
            Log.i(TAG, "[FingerprintScanThread] === START ===");
            FPReaderMgrHandler = Handle;
        }

        public void run() {
            try {
                Log.i(TAG, "[FingerprintScanThread.run()] === START ===");
                while (!isInterrupted()) {

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Log.e(TAG, "[InterruptedException] (FingerprintScanThread.run()) Thread.sleep(10)");
                        e.printStackTrace();
                    }
                }
                Log.d(TAG, "[FingerprintScanThread.run()] After !! [while (!isInterrupted())] !!");
            } catch (Exception e) {
                Log.e(TAG, "[Exception] FingerprintScanThread.run()");
                e.printStackTrace();
            }
        }
    }

    public class SerialDataReceiver extends Thread {
        Handler FPReaderMgrHandler;
        long lRcvTimeLimit = 0;
        int nRcvDataCnt = 0;
        short sCSCal = 0;
        short sCSRcv = 0;
        int nAvailable = 0;
        char cPacketlength = 0;
        byte[] hRcvBuffer;
        boolean bRcvDone = false;   // 데이터 수신완료 여부 (true: 수신 완료, false: 수신 미완료)

        public SerialDataReceiver(Handler Handle) {
            Log.i(TAG, "[SerialDataReceiver(Handle)] === START ===");
            FPReaderMgrHandler = Handle;
        }

        public void run() {
            try {
                Log.i(TAG, "[SerialDataReceiver.run()] === START ===");
                while (!isInterrupted()) {
                    try {
                        if (mInputStream == null) {
                            Log.i(TAG, "[SerialDataReceiver.run()] mInputStream is null!!");
                            return;
                        }

                        if (mInputStream.available() > 0) {
                            lRcvTimeLimit = System.currentTimeMillis() + SERIAL_RECEIVE_TIMEOUT;   // Time limit for receiving data
                            nRcvDataCnt = 0;
                            while (lRcvTimeLimit > System.currentTimeMillis()) {
                                if (mInputStream.available() > 0) {
                                    hRcvBuffer = new byte[mInputStream.available()];
                                    mInputStream.read(hRcvBuffer);
//                                    Log.e(TAG, "[SerialDataReceiver.run()] Length [" + hRcvBuffer.length + "], hRcvBuffer = " + Global.printHexs(hRcvBuffer));
                                    for (int i = 0; i < hRcvBuffer.length; i++) {
                                        if (nRcvDataCnt == 0) {
                                            // STX high
                                            if (hRcvBuffer[i] == FPReaderPacket.STX[0]) {
                                                // STX
                                                hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                                nRcvDataCnt++;
                                            } else {
                                                // No STX high
                                                nRcvDataCnt = 0;
                                            }
                                        } else if (nRcvDataCnt == 1) {
                                            // STX low
                                            if (hRcvBuffer[i] == FPReaderPacket.STX[1]) {
                                                hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                                nRcvDataCnt++;
                                            } else {
                                                // No STX low
                                                nRcvDataCnt = 0;
                                            }
                                        } else if (nRcvDataCnt == 2) {
                                            // Reader ID 1
                                            if (hRcvBuffer[i] == FPReaderPacket.ID_READER[0]) {
                                                hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                                nRcvDataCnt++;
                                            } else {
                                                nRcvDataCnt = 0;
                                            }
                                        } else if (nRcvDataCnt == 3) {
                                            // Reader ID 2
                                            if (hRcvBuffer[i] == FPReaderPacket.ID_READER[1]) {
                                                hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                                nRcvDataCnt++;
                                            } else {
                                                nRcvDataCnt = 0;
                                            }
                                        } else if (nRcvDataCnt == 4) {
                                            // Reader ID 3
                                            if (hRcvBuffer[i] == FPReaderPacket.ID_READER[2]) {
                                                hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                                nRcvDataCnt++;
                                            } else {
                                                nRcvDataCnt = 0;
                                            }
                                        } else if (nRcvDataCnt == 5) {
                                            // Reader ID 4
                                            if (hRcvBuffer[i] == FPReaderPacket.ID_READER[3]) {
                                                hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                                nRcvDataCnt++;
                                            } else {
                                                nRcvDataCnt = 0;
                                            }
                                        } else if (nRcvDataCnt == 6) {
                                            // packet type (packet flag)
                                            hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                            sCSCal = 0;
                                            sCSCal += (int) hRcvData[nRcvDataCnt] & 0xFF;
                                            nRcvDataCnt++;
                                        } else if (nRcvDataCnt == 7) {
                                            // packet length 1
                                            hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                            sCSCal += (int) hRcvData[nRcvDataCnt] & 0xFF;
                                            cPacketlength = (char) (hRcvData[nRcvDataCnt] << 8);
                                            nRcvDataCnt++;
                                        } else if (nRcvDataCnt == 8) {
                                            // packet length 2
                                            hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                            sCSCal += (int) hRcvData[nRcvDataCnt] & 0xFF;
                                            cPacketlength += (int) hRcvData[nRcvDataCnt];
                                            nRcvDataCnt++;
                                            SERIAL_PACKET_EXPECTED_LENGTH = SERIAL_PACKET_FIXEDBASE_LENGTH + cPacketlength;
//                                            Log.d(TAG, "[SerialDataReceiver.run()] sPacketlength = " + Global.ChartoString(cPacketlength) + ", SERIAL_PACKET_EXPECTED_LENGTH = " + SERIAL_PACKET_EXPECTED_LENGTH);
                                        } else if (8 < nRcvDataCnt && nRcvDataCnt < SERIAL_PACKET_EXPECTED_LENGTH - 2) {
                                            hRcvData[nRcvDataCnt] = hRcvBuffer[i];
                                            sCSCal += (int) hRcvData[nRcvDataCnt] & 0xFF;
                                            nRcvDataCnt++;
                                        } else if (nRcvDataCnt == SERIAL_PACKET_EXPECTED_LENGTH - 2) {
                                            // CS high
                                            hRcvData[nRcvDataCnt] = hRcvBuffer[i];

                                            nRcvDataCnt++;
                                        } else if (nRcvDataCnt == SERIAL_PACKET_EXPECTED_LENGTH - 1) {
                                            // CS low
                                            hRcvData[nRcvDataCnt] = hRcvBuffer[i];

                                            sCSRcv = (short) (((hRcvData[nRcvDataCnt - 1] & 0xFF) << 8) | (hRcvData[nRcvDataCnt] & 0xFF));

                                            nRcvDataCnt++;

//                                            Log.d(TAG, "[SerialDataReceiver.run()] hRcvData = " + Global.printHexs(hRcvData, nRcvDataCnt));
//                                            Log.e(TAG, "[SerialDataReceiver.run()] sCSCal = " +   String.format("%04X", sCSCal) + ", sCSRcv = " +   String.format("%04X", sCSRcv));
                                            if (sCSCal == sCSRcv) {
//                                                Log.e(TAG, "[SerialDataReceiver.run()] hRcvData.length = " +   hRcvData.length + ", nRcvDataCnt = " +   nRcvDataCnt);
                                                receivedMsg(hRcvData, nRcvDataCnt);
                                                nRcvDataCnt = 0;
                                                bRcvDone = true;
                                                if (hRcvBuffer.length > SERIAL_PACKET_EXPECTED_LENGTH) {
                                                    try {
                                                        byte[] buffercopy = new byte[SERIAL_PACKET_MAX_LENGTH];
                                                        System.arraycopy(hRcvBuffer, SERIAL_PACKET_EXPECTED_LENGTH + 1, buffercopy, 0, hRcvBuffer.length - (SERIAL_PACKET_EXPECTED_LENGTH + 1));
                                                        System.arraycopy(hRcvBuffer, 0, buffercopy, 0, hRcvBuffer.length);
                                                        lRcvTimeLimit = System.currentTimeMillis() + SERIAL_RECEIVE_TIMEOUT;   // Time limit for receiving data
                                                    } catch (Exception e) {
                                                        Log.e(TAG, "[Exception] The packet received more than two packets!!!");
                                                        e.printStackTrace();
                                                    }
                                                }
                                                else {
                                                    lRcvTimeLimit = System.currentTimeMillis() - 1;   // 타이머 루프를 빠져나온다.
                                                }
                                            }
                                            else {
                                                Log.w(TAG, "[SerialDataReceiver.run()] Checksum is incorrect!!");
                                                nRcvDataCnt = 0;
                                            }
                                        } else {
                                            nRcvDataCnt = 0;
                                        }
                                    }
                                }
                            }   // End of "while (lRcvTimeLimit > System.currentTimeMillis())"
                        }  // After "if (mInputStream.available() > 0)"
                    } catch (Exception e) {
                        Log.e(TAG, "[Exception] @while (!isInterrupted())");
                        e.printStackTrace();
                    }
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Log.e(TAG, "[InterruptedException] (SerialDataReceiver.run()) Thread.sleep(10)");
                        e.printStackTrace();
                    }
                }
                Log.d(TAG, "[SerialDataReceiver.run()] After !! [while (!isInterrupted())] !!");
            } catch (Exception e) {
                Log.e(TAG, "[Exception] (SerialDataReceiver.run())");
                e.printStackTrace();
            }
        }
    }






}