/*************************************************************************
 * DISCLAIMER                                                            *
 * Services performed by FREESCALE in this matter are performed          *
 * AS IS and without any warranty. CUSTOMER retains the final decision   *
 * relative to the total design and functionality of the end product.    *
 * FREESCALE neither guarantees nor will be held liable by CUSTOMER      *
 * for the success of this project. FREESCALE disclaims all warranties,  *
 * express, implied or statutory including, but not limited to,          *
 * implied warranty of merchantability or fitness for a particular       *
 * purpose on any hardware, software ore advise supplied to the project  *
 * by FREESCALE, and or any product resulting from FREESCALE services.   *
 * In no event shall FREESCALE be liable for incidental or consequential *
 * damages arising out of this agreement. CUSTOMER agrees to hold        *
 * FREESCALE harmless against any and all claims demands or actions      *
 * by anyone on account of any damage, or injury, whether commercial,    *
 * contractual, or tortuous, rising directly or indirectly as a result   *
 * of the advise or assistance supplied CUSTOMER in connection with      *
 * product, services or goods supplied under this Agreement.             *
 *************************************************************************/
/*******************************************************************
  Copyright (c) 2011 Freescale Semiconductor
  \file     	Main.c
  \brief    	GUI for Smart Card Reader
  \author   	Freescale Semiconductor
  \version      0.2
  \date     	16/Aug/2011
*********************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Utility;


namespace USB_GUI
{
    public partial class Form1 : Form
    {
        byte[] InterruptBuffer = new byte[8];
        byte[] OutBuffer = new byte[64];
        byte[] InBuffer = new byte[64];
        const byte WRITE_LEDS = 0xE0;
        static int counter = 0;
        byte LEDstatus = 0x00;


        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            JM60.OpenConnection();
            timer1.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            JM60.StopReadingInterruptEndpoint();
            JM60.CloseConnection();
            timer1.Stop();
        }

        private void JM60_onDeviceConnect()
        {
            label1.Text = "USB Connected";
            label1.ForeColor = Color.Green;
            JM60.SetTimeOut(1, 2000);
            JM60.StartReadingInterruptEndPoint(2, 8);

            OutBuffer[0] = 0x03;       // Length == 3, read back smart card inserted status
            OutBuffer[1] = 0x00;
            OutBuffer[2] = 0x00; 
            OutBuffer[3] = 0x00;
            OutBuffer[63] = 0xaa;      // For test
            
            JM60.WriteData(3, OutBuffer, 64);
            JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

            if (InBuffer[1] == 0x01)
            {
                label4.Text = "Card Inserted";
                label4.ForeColor = Color.Green;
            }
            else if (InBuffer[1] == 0x02)
            {
                label4.Text = "No Card";
                label4.ForeColor = Color.Red;
            }

        }

        private void JM60_onDeviceDisconnect()
        {
            label1.Text = "USB Disconnected";
            label1.ForeColor = Color.Red;

            label4.Text = "No Card";
            label4.ForeColor = Color.Red;
        }

        private string DataToString(int size, byte[] buffer)
        {
            int i;
            string result = null;
        
            for (i = 0; i < size; i++)
            {
                result += buffer[i].ToString("X2") + " ";
            }
          
            return result;
        }

        private string DataToResponseStr(byte[] buffer)
        {
            int i;
            string result = null;
            
            if (buffer[0] > 2)     // buffer[0] is data length
            {
                result += "Data = ";
                for (i = 1;i <= buffer[0]-2; i++) 
                {
                    result += buffer[i].ToString("X2") + " ";
                }
            }

            return result;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (label1.Text == "USB Connected")
            {
                OutBuffer[0] = 0x05;   // APDU length
                OutBuffer[1] = 0x00;
                OutBuffer[2] = 0x84;   // Get Challenge
                OutBuffer[3] = 0x00;
                OutBuffer[4] = 0x00;
                OutBuffer[5] = 0x08;   // Le

                JM60.WriteData(3, OutBuffer, 64);
                JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

                if (InBuffer[0] > 2)
                {
                    label2.Text = DataToResponseStr(InBuffer);
                }
                else if (InBuffer[0] == 0x02)
                {
                    if (InBuffer[1] == 0x67 && InBuffer[2] == 0x00)
                    {
                        label2.Text = "Incorrect length";
                    }
                    else if (InBuffer[1] == 0x6A && InBuffer[2] == 0x81)
                    {
                        label2.Text = "Function not supported";
                    }
                }
            }
        }

        private byte get_response(byte number)
        {
            OutBuffer[0] = 0x05;       // APDU length
            OutBuffer[1] = 0x00;
            OutBuffer[2] = 0xC0;       // Create file
            OutBuffer[3] = 0x00;
            OutBuffer[4] = 0x00;
            OutBuffer[5] = number;     // Le
                
            JM60.WriteData(3, OutBuffer, 64);
            JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

            return 0;
        }

        private byte create_mf()
        {
            OutBuffer[0] = 18;         // APDU length
            OutBuffer[1] = 0x80;
            OutBuffer[2] = 0xE0;       // Create file
            OutBuffer[3] = 0x3F;
            OutBuffer[4] = 0x00;
            OutBuffer[5] = 0x0d;       // Lc
            OutBuffer[6] = 0x38;
            OutBuffer[7] = 0xFF;
            OutBuffer[8] = 0xFF; 
            OutBuffer[9] = 0xF0;
            OutBuffer[10] = 0xF0;
            OutBuffer[11] = 0xFF; 
            OutBuffer[12] = 0xFF;
            OutBuffer[13] = 0xFF;
            OutBuffer[14] = 0xFF; 
            OutBuffer[15] = 0xFF;
            OutBuffer[16] = 0xFF;
            OutBuffer[17] = 0xFF; 
            OutBuffer[18] = 0xFF;
           
            JM60.WriteData(3, OutBuffer, 64);
            JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

            if (!(InBuffer[1] == 0x90 && InBuffer[2] == 0x00))
            {
                return 0x01;
            }
            else
                return 0x00;
        }


        private byte select_mf( )
        {
            OutBuffer[0] = 0x07;       // APDU length
            OutBuffer[1] = 0x00;
            OutBuffer[2] = 0xA4;       // Select file
            OutBuffer[3] = 0x00;
            OutBuffer[4] = 0x00;
            OutBuffer[5] = 0x02;       // Lc
            OutBuffer[6] = 0x3F;
            OutBuffer[7] = 0x00;

            JM60.WriteData(3, OutBuffer, 64);
            JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

            if (!(InBuffer[1] == 0x61 && InBuffer[2] == 0x12))
            {
                return 0x01;
            }
            else
            {
                get_response(0x12);
                return 0x00;
            }
        }

        private byte create_ef(byte number)
        {
            OutBuffer[0] = 12;         // APDU length
            OutBuffer[1] = 0x80;
            OutBuffer[2] = 0xE0;       // Create file
            OutBuffer[3] = 0x00;
            OutBuffer[4] = (byte)(number | 0x80);
            OutBuffer[5] = 0x07;       // Lc
            OutBuffer[6] = 0x28;
            OutBuffer[7] = 0x00;
            OutBuffer[8] = 0x10;
            OutBuffer[9] = 0xF0;
            OutBuffer[10] = 0xF0;
            OutBuffer[11] = 0xFF;
            OutBuffer[12] = 0xFF;
            
            JM60.WriteData(3, OutBuffer, 64);
            JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

            if (!(InBuffer[1] == 0x90 && InBuffer[2] == 0x00))
            {
                return 0x01;
            }
            else
                return 0x00;
        }

        private byte select_ef(byte number)
        {
            OutBuffer[0] = 0x07;       // APDU length
            OutBuffer[1] = 0x00;
            OutBuffer[2] = 0xA4;       // Select file
            OutBuffer[3] = 0x00;
            OutBuffer[4] = 0x00;
            OutBuffer[5] = 0x02;       // Lc
            OutBuffer[6] = 0x00;
            OutBuffer[7] = number;

            JM60.WriteData(3, OutBuffer, 64);
            JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

            if (!(InBuffer[1] == 0x90 && InBuffer[2] == 0x00))
            {
                return 0x01;
            }
            else
            {
                return 0x00;
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (label1.Text == "USB Connected")
            {
                if (!(select_mf() == 0x00))
                {
                    if (!(create_mf() == 00))
                    {
                        return;                           // failed create mf
                    }
                    select_mf();
                }

                if (!(select_ef(0x10) == 0x00))
                {
                    if (!(create_ef(0x10) == 00))
                    {
                        return;                           // failed create mf
                    }
                    select_ef(0x10);
                }

                byte[] tempBuffer = new byte[64];
                int Data_length = 0;
                string hexString = textBox1.Text;
                int i, discarded;
                byte number = 0x10;                        // File ID

                byte[] byteArray = HexEncoding.GetBytes(hexString, out discarded);
                Data_length = HexEncoding.GetByteCount(hexString);

                OutBuffer[0] = (byte)(Data_length + 5);    // APDU length
                OutBuffer[1] = 0x00;
                OutBuffer[2] = 0xD6;                       // Update binary
                OutBuffer[3] = (byte)(number | 0x80);
                OutBuffer[4] = 0x00;
                OutBuffer[5] = (byte)(Data_length);        // Lc
                for (i = 0; i < Data_length; i++)
                {
                    OutBuffer[6 + i] = byteArray[i];
                }

                JM60.WriteData(3, OutBuffer, 64);
                JM60.ReadBulkEndpoint(4, ref InBuffer, 64);
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            int i;
            if (label1.Text == "USB Connected")
            {
                OutBuffer[0] = 0x05;   // APDU length
                OutBuffer[1] = 0x00;
                OutBuffer[2] = 0xB0;   // Read binary
                OutBuffer[3] = 0x90;   // 0b10010000, Bit 8 =1, short File ID = 0x10
                OutBuffer[4] = 0x00;   // Offset
                OutBuffer[5] = 0x10;   // File length

                JM60.WriteData(3, OutBuffer, 64);
                JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

                if (InBuffer[0] > 2)
                {
                    byte[] tempbuffer = new byte[InBuffer[0] - 2];
                    for (i = 0; i < (InBuffer[0] - 2); i++)
                        tempbuffer[i] = InBuffer[i + 1];
                    textBox1.Text = HexEncoding.ToString(tempbuffer);
                }
            }

        }

        private void JM60_onReadComplete()
        {
            JM60.ReadInterruptEndpoint(ref InterruptBuffer, 8);
          
            if (InterruptBuffer[1] == 0x01 && label1.Text == "USB Connected")
            {
                label4.Text = "Card Inserted";
                label4.ForeColor = Color.Green;
            }
            else if (InterruptBuffer[1] == 0x02)
            {
                label4.Text = "No Card";
                label4.ForeColor = Color.Red;
            }
        }

        private string ResponseDecode(byte[] buffer)
        {
            int i;
            string result = null;

            if (buffer[0] > 0x02)                          // buffer[0] is data length
            {
                result += "Data = ";
                for (i = 1; i <= buffer[0] - 2; i++)
                {
                    result += buffer[i].ToString("X2") + " ";
                }
                result += "SW1 = " + buffer[i].ToString("X2") + " ";
                result += "SW2 = " + buffer[++i].ToString("X2");
            }
            else if (buffer[0] == 0x02)
            {
                result += "SW1 = " + buffer[1].ToString("X2") + " ";
                result += "SW2 = " + buffer[2].ToString("X2");
            }
            else
            {
                result = "Wrong data!";
            }

            return result;
        }

        private void button6_Click(object sender, EventArgs e)
        {
            byte[] tempBuffer = new byte[64];
            int CMD_length = 0;
            string hexString = textBox2.Text;
            int i,discarded;

            if (label1.Text == "USB Connected")
            {
                byte[] byteArray = HexEncoding.GetBytes(hexString, out discarded);
                CMD_length = HexEncoding.GetByteCount(hexString);

                OutBuffer[0] = (byte)CMD_length;           // APDU length
                for (i = 1; i <= OutBuffer[0]; i++)
                {
                    OutBuffer[i] = byteArray[i - 1];
                }

                JM60.WriteData(3, OutBuffer, 64);
                JM60.ReadBulkEndpoint(4, ref InBuffer, 64);

                label3.Text = ResponseDecode(InBuffer);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if(LEDstatus == 0x00)
                LEDstatus = 1;
            else
                LEDstatus = 0;

            InterruptBuffer[0] = LEDstatus;
            counter++;

            if(label1.Text == "USB Connected")
              JM60.WriteData(1, InterruptBuffer, 1);
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}
