IDTech Windows SDK Guide  1.00.029
API reference for UniPay
Sample Project Tutorial

Using Visual Studio 2015, we will create a C# sample project that will interface with the UniPay and will perform the following activities:

  • Get firmware version
  • Display ICC Status (card inserted/removed, ICC power on/off)
  • Turn on/off ICC reader
  • Start/Cancel MSR reading
  • Show log of all data going to/from UniPay

Step 1: Create New Project

Create a new Blank App (Universal Windows) in Visual Studio. In our example, we use project name UniPay_Simple_Demo_UWP.

new_project_uwp.png

On the following popup, choose the target and minimum versions that your application will support. We have chosen the following for our demo application:

versions_uwp.png

Step 2: Import Libraries

Import the Necessary Libraries

Step 3: Add Device Details

Add Device Details to the Application's Manifest

Step 4: Design Interface

Use the Designer to layout buttons/fields
Open your designer and add items so it contains the following buttons/fields:

  • Add buttons to execute the following functions:
    • Show Firmware
    • Show ICC Status
    • Turn ON ICC Reader
    • Turn OFF ICC Reader
    • Start MSR Swipe
    • Cancel MSR Swipe
  • Add a text box to communicate data from the UniPay.
  • Add a text box for the log of UniPay.
  • Add a text box to display the connection status.


UniPay_app_uwp.png

Step 5: Configure the Project File

In the start of the class file, perform the following:

  • Add Using Statements to Utilize Library
  • Set callback method in the class initializer. Reference: Initialize UniPay
  • Implement the button methods Click handlers for button press code execution
    private void btnGetFirmware_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    string firmwareVersion = "";
    byte[] reData = { };
    RETURN_CODE rt = IDT_UniPay.SharedController.device_getFirmwareVersion(ref firmwareVersion);
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    SetOutputText("Firmware Ver: " + firmwareVersion + "\r\n");
    System.Diagnostics.Debug.WriteLine("Firmware Ver: " + firmwareVersion);
    }
    else
    {
    SetOutputText("Get Firmware Fail Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("Get Firmware Fail Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnGetICCStatus_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    byte status = 0;
    RETURN_CODE rt = IDT_UniPay.SharedController.icc_getICCReaderStatus(ref status);
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    byte bit0 = (byte)(status & 0x01);
    byte bit1 = (byte)((status & 0x02) >> 1);
    SetOutputText("ICC Reader Status : " + (bit0 == 1 ? "[ICC Powered] " : "[ICC Power Not Ready] ") + (bit1 == 1 ? "[Card Seated]" : "[Card Not Seated]") + "\r\n");
    System.Diagnostics.Debug.WriteLine("ICC Reader Status : " + (bit0 == 1 ? "[ICC Powered] " : "[ICC Power Not Ready] ") + (bit1 == 1 ? "[Card Seated]" : "[Card Not Seated]"));
    }
    else
    {
    SetOutputText("Get ICC Reader Status Failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("Get ICC Reader Status Failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnPowerOnICC_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    byte[] ATR = null;
    RETURN_CODE rt = IDT_UniPay.SharedController.icc_powerOnICC(ref ATR);
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    SetOutputText("ATR:" + string.Concat(ATR.ToArray().Select(b => b.ToString("X2")).ToArray()) + "\r\n");
    SetOutputText("ICC Powered On successfully\r\n");
    System.Diagnostics.Debug.WriteLine("ICC Powered On successfully");
    }
    else
    {
    SetOutputText("ICC Powered On failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("ICC Powered On failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnPowerOffICC_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    RETURN_CODE rt = IDT_UniPay.SharedController.icc_powerOffICC();
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    SetOutputText("ICC Powered Off successfully\r\n");
    System.Diagnostics.Debug.WriteLine("ICC powered Off successfully");
    }
    else
    {
    SetOutputText("ICC Powered Off failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("ICC powered Off failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnStartMSRTransaction_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    RETURN_CODE rt = IDT_UniPay.SharedController.msr_startMSRSwipe(60);
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    //EY: MSR BLUE LED BLINK
    SetOutputText("MSR Turned On successfully; Ready to swipe\r\n");
    System.Diagnostics.Debug.WriteLine("MSR Turned On successfully; Ready to swipe");
    }
    else
    {
    SetOutputText("MSR Turned On failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("MSR Turned On failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnCancelMSRTransaction_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    RETURN_CODE rt = IDT_UniPay.SharedController.msr_cancelMSRSwipe();
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    SetOutputText("MSR Turned Off successfully\r\n");
    System.Diagnostics.Debug.WriteLine("MSR Turned Off successfully");
    }
    else
    {
    SetOutputText("MSR Turned Off failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("MSR Turned Off failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }

    Note that all the the click handlers' code are ran asynchronously. At least the device command needs to be executed asynchronously or it will block the UI thread. The UWP API that is used by the IDTechSDK_UWP library for communication with HID devices is asynchronous.

Step 6: Configure Callback

The callback is used to receive important SDK data (messages, log info and transaction results). Reference: Implement the Callback Function

private void MessageCallBack(IDTechSDK.IDT_DEVICE_Types type, DeviceState state, byte[] data, IDTTransactionData cardData, EMV_Callback emvCallback, RETURN_CODE transactionResultCode)
{
switch (state)
{
case DeviceState.ToConnect:
//A connection attempt is starting for IDT_DEVICE_TYPES type
SetOutputText("Callback:ToConnect\n");
break;
case DeviceState.DefaultDeviceTypeChange:
//The SDK is changing the default device to IDT_DEVICE_TYPES type
SetOutputText("Callback:DefaultDeviceTypeChange\n");
connectionStatus.Text = "UniPay connected.";
connectionStatus.Background = new SolidColorBrush(Windows.UI.Colors.Green);
break;
case DeviceState.Connected:
//A connection has been made to IDT_DEVICE_TYPES type
SetOutputText("Callback:Connected\n");
connectionStatus.Text = "UniPay connected.";
connectionStatus.Background = new SolidColorBrush(Windows.UI.Colors.Green);
break;
case DeviceState.Disconnected:
//A disconnection has occured with IDT_DEVICE_TYPES type
SetOutputText("Callback:Disconnected\n");
connectionStatus.Text = "UniPay not connected.";
connectionStatus.Background = new SolidColorBrush(Windows.UI.Colors.Red);
break;
case DeviceState.ConnectionFailed:
//A connection attempt has failed for IDT_DEVICE_TYPES type
SetOutputText("Callback:ConnectionFailed\n");
break;
case DeviceState.TransactionData:
//Transaction data is beign returned in IDTTransactionData cardData
SetOutputText("Callback:TransactionData\n");
if (cardData == null) break;
//output parsed card data
SetOutputText("Return Code MSR: " + transactionResultCode.ToString() + "\r\n");
displayCardData(cardData);
break;
case DeviceState.DataReceived:
//Low-level data received for IDT_DEVICE_TYPES type
SetOutputTextLog(GetTimestamp() + " IN: " + Common.getHexStringFromBytes(data));
break;
case DeviceState.DataSent:
//Low-level data sent for IDT_DEVICE_TYPES type
SetOutputTextLog(GetTimestamp() + " OUT: " + Common.getHexStringFromBytes(data));
break;
case DeviceState.CommandTimeout:
SetOutputText("Callback:CommandTimeout\n");
//Command timeout has occurred for IDT_DEVICE_TYPES type
break;
case DeviceState.ToSwipe:
//Awaiting a swipe for IDT_DEVICE_TYPES type
SetOutputText("Callback:ToSwipe\n");
break;
case DeviceState.MSRDecodeError:
//Awaiting a swipe for IDT_DEVICE_TYPES type
SetOutputText("Callback:MSRDecodeError\n");
break;
case DeviceState.ToTap:
//Awaiting a contactless tap for IDT_DEVICE_TYPES type
SetOutputText("Callback:ToTap\n");
break;
case DeviceState.SwipeTimeout:
//Waiting for swipe timed out
SetOutputText("Callback:SwipeTimeout\n");
break;
case DeviceState.TransactionCancelled:
//Transaction has been cancelled
SetOutputText("Callback:TransactionCancelled\n");
break;
case DeviceState.DeviceTimeout:
//Waiting for EMV transaction to complete timed out
SetOutputText("Callback:DeviceTimeout\n");
break;
case DeviceState.TransactionFailed:
//Transaction failed to complete
SetOutputText("Callback:TransactionFailed\n");
break;
case DeviceState.EMVCallback:
//Callback during EMV transaction retrieved from EMV_Callback emvCallback
SetOutputText("Callback:EMVCallback\n");
break;
default:
break;
}
}
public static String GetTimestamp()
{
DateTime value = DateTime.Now;
return value.ToString("HH:mm:ss.fff");
}
private void displayCardData(IDTTransactionData cardData)
{
string text = "";
if (cardData.Event == EVENT_TRANSACTION_DATA_Types.EVENT_TRANSACTION_PIN_DATA)
{
SetOutputText("PIN Data received:\r\nKSN: " + cardData.pin_KSN + "\r\nPINBLOCK: " + cardData.pin_pinblock + "\r\n");
return;
}
if (cardData.Event == EVENT_TRANSACTION_DATA_Types.EVENT_TRANSACTION_DATA_CARD_DATA)
{
SetOutputText("Data received: (Length [" + cardData.msr_rawData.Length.ToString() + "])\n" + string.Concat(cardData.msr_rawData.ToArray().Select(b => b.ToString("X2")).ToArray()) + "\r\n");
System.Diagnostics.Debug.WriteLine("Data received: (Length [" + cardData.msr_rawData.Length.ToString() + "])\n" + string.Concat(cardData.msr_rawData.ToArray().Select(b => b.ToString("X2")).ToArray()));
}
if (cardData.device_RSN != null && cardData.device_RSN.Length > 0)
text += "Serial Number: " + cardData.device_RSN + "\r\n";
if (cardData.msr_track1Length > 0)
text += "Track 1: " + cardData.msr_track1 + "\r\n";
if (cardData.msr_encTrack1 != null)
text += "Track 1 Encrypted: " + Common.getHexStringFromBytes(cardData.msr_encTrack1) + "\r\n";
if (cardData.msr_hashTrack1 != null)
text += "Track 1 Hash: " + Common.getHexStringFromBytes(cardData.msr_hashTrack1) + "\r\n";
if (cardData.msr_track2Length > 0)
text += "Track 2: " + cardData.msr_track2 + "\r\n";
if (cardData.msr_encTrack2 != null)
text += "Track 2 Encrypted: " + Common.getHexStringFromBytes(cardData.msr_encTrack2) + "\r\n";
if (cardData.msr_hashTrack2 != null)
text += "Track 2 Hash: " + Common.getHexStringFromBytes(cardData.msr_hashTrack2) + "\r\n";
if (cardData.msr_track3Length > 0)
text += "Track 3: " + cardData.msr_track3 + "\r\n";
if (cardData.msr_encTrack3 != null)
text += "Track 3 Encrypted: " + Common.getHexStringFromBytes(cardData.msr_encTrack3) + "\r\n";
if (cardData.msr_hashTrack3 != null)
text += "Track 3 Hash: " + Common.getHexStringFromBytes(cardData.msr_hashTrack3) + "\r\n";
if (cardData.msr_KSN != null)
text += "KSN: " + Common.getHexStringFromBytes(cardData.msr_KSN) + "\r\n";
if (cardData.emv_clearingRecord != null)
{
if (cardData.emv_clearingRecord.Length > 0)
{
text += "\r\nCTLS Clearing Record: \r\n";
text += Common.getHexStringFromBytes(cardData.emv_clearingRecord) + "\r\n";
Dictionary<string, string> dict = Common.processTLVUnencrypted(cardData.emv_clearingRecord);
foreach (KeyValuePair<string, string> kvp in dict) text += kvp.Key + ": " + kvp.Value + "\r\n";
text += "\r\n\r\n";
}
}
if (cardData.emv_unencryptedTags != null)
{
if (cardData.emv_unencryptedTags.Length > 0)
{
text += "\r\n======================== \r\n";
text += "\r\nUnencrypted Tags: \r\n";
text += Common.getHexStringFromBytes(cardData.emv_unencryptedTags) + "\r\n\r\n";
text += tlvToValues(cardData.emv_unencryptedTags);
text += "\r\n======================== \r\n";
}
}
if (cardData.emv_encryptedTags != null)
{
if (cardData.emv_encryptedTags.Length > 0)
{
text += "\r\n======================== \r\n";
text += "\r\nEncrypted Tags: \r\n";
text += Common.getHexStringFromBytes(cardData.emv_encryptedTags) + "\r\n\r\n";
text += tlvToValues(cardData.emv_encryptedTags);
text += "\r\n======================== \r\n";
}
}
if (cardData.emv_maskedTags != null)
{
if (cardData.emv_maskedTags.Length > 0)
{
text += "\r\n======================== \r\n";
text += "\r\nMasked Tags: \r\n";
text += Common.getHexStringFromBytes(cardData.emv_maskedTags) + "\r\n\r\n";
text += tlvToValues(cardData.emv_maskedTags);
text += "\r\n======================== \r\n";
}
}
text += "ICC Present: ";
text += (cardData.iccPresent == 1 ? "TRUE" : "FALSE") + "\r\n";
text += "is CTLS: ";
text += (cardData.isCTLS == 1 ? "TRUE" : "FALSE") + "\r\n";
if (cardData.Event == EVENT_TRANSACTION_DATA_Types.EVENT_TRANSACTION_DATA_EMV_DATA)
{
if (cardData.isCTLS == 2) text += "Capture Encrypt Type: " + ((cardData.emv_encryptionMode == EMV_ENCRYPTION_MODE.EMV_ENCRYPTION_MODE_TDES) ? "TDES" : "AES") + "\r\n";
switch (cardData.emv_resultCode)
{
case EMV_RESULT_CODE.EMV_RESULT_CODE_APPROVED:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_APPROVED" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_APPROVED_OFFLINE:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_APPROVED_OFFLINE" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_DECLINED_OFFLINE:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_DECLINED_OFFLINE" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_DECLINED:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_DECLINED" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_GO_ONLINE:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_GO_ONLINE" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_CALL_YOUR_BANK:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_CALL_YOUR_BANK" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_NOT_ACCEPTED:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_NOT_ACCEPTED" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_FALLBACK_TO_MSR:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_FALLBACK_TO_MSR" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_TIMEOUT:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_TIMEOUT" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_AUTHENTICATE_TRANSACTION" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_SWIPE_NON_ICC:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_SWIPE_NON_ICC" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_CTLS_TWO_CARDS:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_CTLS_TWO_CARDS" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_CTLS_TERMINATE:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_CTLS_TERMINATE" + "\r\n");
break;
case EMV_RESULT_CODE.EMV_RESULT_CODE_CTLS_TERMINATE_TRY_ANOTHER:
text += ("EMV RESULT: " + "EMV_RESULT_CODE_CTLS_TERMINATE_TRY_ANOTHER" + "\r\n");
break;
}
}
SetOutputText(text);
}
private string tlvToValues(byte[] tlv)
{
string text = "";
Dictionary<string, string> dict = Common.processTLVUnencrypted(tlv);
foreach (KeyValuePair<string, string> kvp in dict) text += kvp.Key + ": " + kvp.Value + "\r\n";
return text;
}
delegate void SetTextCallback(string text);
private async void SetOutputText(string text)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
tbOutput.Text = text + "\r\n" + tbOutput.Text;
});
}
private void SetOutputTextLog(string text)
{
logOutput.Text = text + "\r\n" + logOutput.Text;
}