IDTech Windows SDK Guide  1.2.177.4
API reference for Vendi
Sample Project Tutorial

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

  • Get firmware version
  • Perform MSR Transaction
  • Perform CTLS Transaction
  • Connect to either USB or Serial Versions of Vendi.
  • Show log of all data going to/from Vendi

Step 1: Create New Project

Create a new Blank App (Universal Windows) in Visual Studio. In our example, we use project name Vendi_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:

  • Radio buttons for USB and COM selection. For COM selection, add a text box to specify COM port.
  • Add buttons to execute the following functions:
    • Get Firmware
    • Start MSR
    • Cancel MSR
    • Start CTLS Transaction
    • Cancel CTLS Transaction
  • Add a text box to communicate data from the Vendi.
  • Add a text box for the log of Vendi.
  • Add a text box to display the connection status.


Vendi_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 and initialize Vendi singleton object in the class initializer. Reference: Initialize Vendi
  • Implement the radio button methods Click handlers to set the proper interface for SDK communications
    private void rbInterface_Click(object sender, RoutedEventArgs e)
    {
    if (rbUSB.IsChecked ?? false)
    {
    Task.Run(() => IDT_Vendi.useUSB());
    return;
    }
    Int32 portNumber = Convert.ToInt32(tbCOMPort.Text);
    Task.Run(() => IDT_Vendi.useSerialPort(portNumber));
    }

  • Implement the button methods Click handlers for button press code execution
    private void btnGetFirmwareVersion_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    string firmwareVersion = "";
    byte[] reData = { };
    RETURN_CODE rt = IDT_Vendi.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 btnStartMSR_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    RETURN_CODE rt = IDT_Vendi.SharedController.msr_startMSRSwipe(60);
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    // continueMSR = true;
    //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("Start Swipe Failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("Start Swipe Failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnCancelMSR_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    RETURN_CODE rt = IDT_Vendi.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));
    }
    });
    }
    private void btnStartCTLSTransaction_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    byte[] additionalTags = new byte[] { 0x8E, 0x5A };
    RETURN_CODE rt = IDT_Vendi.SharedController.ctls_startTransaction(1.00, 0, 2, 0, 30, additionalTags);
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    SetOutputText("Start CTLS Successful\r\n");
    System.Diagnostics.Debug.WriteLine("Start CTLS Successful");
    }
    else
    {
    SetOutputText("Start CTLS failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("Start CTLS failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt));
    }
    });
    }
    private void btnCancelCTLSTransaction_Click(object sender, RoutedEventArgs e)
    {
    Task.Run(() =>
    {
    RETURN_CODE rt = IDT_Vendi.SharedController.ctls_cancelTransaction();
    if (rt == RETURN_CODE.RETURN_CODE_DO_SUCCESS)
    {
    SetOutputText("Cancel Transaction Successful\r\n");
    System.Diagnostics.Debug.WriteLine("Cancel Transaction Successful");
    }
    else
    {
    SetOutputText("Cancel Transaction failed Error Code: " + "0x" + String.Format("{0:X}", (ushort)rt) + ": " + IDTechSDK.errorCode.getErrorString(rt) + "\r\n");
    System.Diagnostics.Debug.WriteLine("Cancel Transaction 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");
break;
case DeviceState.Connected:
//A connection has been made to IDT_DEVICE_TYPES type
SetOutputText("Callback:Connected\n");
connectionStatus.Text = "Vendi 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 = "Vendi 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");
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.CardAction:
if (data != null & data.Length > 0)
{
CARD_ACTION action = (CARD_ACTION)data[0];
StringBuilder sb = new StringBuilder("Card Action Request: ");
if ((action & CARD_ACTION.CARD_ACTION_INSERT) == CARD_ACTION.CARD_ACTION_INSERT) sb.Append("INSERT ");
if ((action & CARD_ACTION.CARD_ACTION_REINSERT) == CARD_ACTION.CARD_ACTION_REINSERT) sb.Append("REINSERT ");
if ((action & CARD_ACTION.CARD_ACTION_REMOVE) == CARD_ACTION.CARD_ACTION_REMOVE) sb.Append("REMOVE ");
if ((action & CARD_ACTION.CARD_ACTION_SWIPE) == CARD_ACTION.CARD_ACTION_SWIPE) sb.Append("SWIPE ");
if ((action & CARD_ACTION.CARD_ACTION_SWIPE_AGAIN) == CARD_ACTION.CARD_ACTION_SWIPE_AGAIN) sb.Append("SWIPE_AGAIN ");
if ((action & CARD_ACTION.CARD_ACTION_TAP) == CARD_ACTION.CARD_ACTION_TAP) sb.Append("TAP ");
if ((action & CARD_ACTION.CARD_ACTION_TAP_AGAIN) == CARD_ACTION.CARD_ACTION_TAP_AGAIN) sb.Append("TAP_AGAIN ");
SetOutputText(sb.ToString() + "\n");
}
break;
case DeviceState.MSRDecodeError:
//Awaiting a swipe for IDT_DEVICE_TYPES type
SetOutputText("Callback:MSRDecodeError\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";
}
}
if (cardData.emv_hasAdvise) text += "CARD RESPONSE HAS ADVISE" + "\r\n";
if (cardData.emv_hasReversal) text += "CARD RESPONSE HAS REFERSAL" + "\r\n";
if (cardData.iccPresent == 1) text += "ICC Present: TRUE" + "\r\n";
if (cardData.iccPresent == 2) text += "ICC Present: FALSE" + "\r\n";
if (cardData.isCTLS == 1) text += "CTLS Capture: TRUE" + "\r\n";
if (cardData.isCTLS == 2) text += "CTLS Capture: FALSE" + "\r\n";
if (cardData.msr_extendedField != null && cardData.msr_extendedField.Length > 0)
text += "Extended Field Bytes: " + Common.getHexStringFromBytes(cardData.msr_extendedField) + "\r\n";
if (cardData.captureEncryptType == CAPTURE_ENCRYPT_TYPE.CAPTURE_ENCRYPT_TYPE_TDES)
text += "Encryption Type: TDES\r\n";
if (cardData.captureEncryptType == CAPTURE_ENCRYPT_TYPE.CAPTURE_ENCRYPT_TYPE_AES)
text += "Encryption Type: AES\r\n";
if (cardData.captureEncryptType == CAPTURE_ENCRYPT_TYPE.CAPTURE_ENCRYPT_TYPE_NONE)
text += "Encryption Type: NONE\r\n";
if (cardData.captureEncryptType != CAPTURE_ENCRYPT_TYPE.CAPTURE_ENCRYPT_TYPE_NONE)
{
if (cardData.msr_keyVariantType == KEY_VARIANT_TYPE.KEY_VARIANT_TYPE_DATA)
text += "Key Type: Data Variant\r\n";
else if (cardData.msr_keyVariantType == KEY_VARIANT_TYPE.KEY_VARIANT_TYPE_PIN)
text += "Key Type: PIN Variant\r\n";
}
if (cardData.mac != null)
text += "MAC: " + Common.getHexStringFromBytes(cardData.mac) + "\r\n";
if (cardData.macKSN != null)
text += "MAC KSN: " + Common.getHexStringFromBytes(cardData.macKSN) + "\r\n";
if (cardData.Event == EVENT_TRANSACTION_DATA_Types.EVENT_TRANSACTION_DATA_EMV_DATA)
{
if ((cardData.isCTLS != 1) && (cardData.captureEncryptType != CAPTURE_ENCRYPT_TYPE.CAPTURE_ENCRYPT_TYPE_NONE)) text += "Capture Encrypt Type: " + ((cardData.captureEncryptType == CAPTURE_ENCRYPT_TYPE.CAPTURE_ENCRYPT_TYPE_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;
}