Need help communicating with a smart card reader

I'm wondering if anyone has had any success with using ignition scripting to read from a card reader. I built some code that can connect to a reader but doesn't return the data I am expecting. If anyone could provide some guidance for what the code should be, or if they've run into a similar issue.

import javax.smartcardio as smartcardio
from array import array

def bytes_to_hex(byte_array):
    """Convert byte array to a hexadecimal string representation."""
    return ''.join(['{:02X}'.format(b) for b in byte_array])

def read_smart_card():
    try:
        # Step 1: Obtain a list of available card terminals
        print("Retrieving list of card terminals...")
        factory = smartcardio.TerminalFactory.getDefault()
        terminals = factory.terminals().list()

        # Check if any terminals are available
        if not terminals:
            print("No card terminals available.")
            return

        # Step 2: Connect to the first available card terminal
        terminal = terminals.get(1)  # You may need to adjust the index based on your setup
        print("Using terminal: {}".format(terminal.getName()))

        # Check if a card is present in the terminal
        if terminal.isCardPresent():
            print("Card detected. Attempting to connect...")
            card = terminal.connect("*")  # Connect to the card
            print("Card connected successfully.")

            # Obtain the basic communication channel with the card
            channel = card.getBasicChannel()

            # Step 3: Send an APDU command to the card
            # This APDU command is an example and may need to be replaced with one specific to your card
            print("Sending APDU command to the card...")
            commandAPDU = smartcardio.CommandAPDU(array('B', [0x00, 0xB0, 0x00, 0x00, 0x00]))
            response = channel.transmit(commandAPDU)


            # Step 4: Process and display the response from the card
            responseData = response.getData()
            print("Response received.")
            print("Response data: {}".format(responseData))
            print("Response data (hex): {}".format(bytes_to_hex(responseData)))

            # Close the connection
            card.disconnect(False)
            print("Card disconnected.")
        else:
            print("No card present in terminal.")
    except Exception as e:
            print("An error occurred:", e)
           
# Run the smart card reader
read_smart_card()

If you were curious about the output console, this is what I am seeing:

Retrieving list of card terminals...
Using terminal: SCM Microsystems Inc. SCR33x USB Smart Card Reader 0
Card detected. Attempting to connect...
Card connected successfully.
Sending APDU command to the card...
Response received.
Response data: array('b', [0, -80, 0])
Response data (hex): 00-5000
Card disconnected.

What data are you expecting? Do you have documentation about the command and response formats?

Maybe it would make some more sense if I provided some more background.

I have this Python code that uses c_types, and I can get it to run in Visual Studio. The issue comes from the fact that I can't use it in Jython, so I have been trying to convert it but am struggling to do so.

import ctypes


# Use this to generate error codes
def convert_to_error_code(result: int) -> str:
    
    # Convert to unsigned 32 int
    result = ctypes.c_uint32(result).value

    # Convert to hex to get error code
    result = hex(result)

    return result


# Load Winscard DLL
winscard_dll = ctypes.WinDLL("C:\\Windows\\SysWOW64\\WinSCard.dll")


# Establish the resource manager context within which database operations are performed
SCARD_SCOPE_USER = ctypes.c_int(0)
phContext = ctypes.c_int(0)

result = winscard_dll.SCardEstablishContext(SCARD_SCOPE_USER, None, None, ctypes.byref(phContext))
print(f"OS Response of Establishing Context Was: {convert_to_error_code(result)}")


# Get list of smart card readers hooked up to the system
smart_card_readers = ctypes.create_string_buffer(800)
pcchReaders = ctypes.c_uint32(400)
result = winscard_dll.SCardListReadersA(phContext, None, smart_card_readers, ctypes.byref(pcchReaders))
print(f"OS Response of Listing Smart Card Readers Was: {convert_to_error_code(result)}")


# Examine returned list of smart card readers and parse out the individual smart card readers
smart_card_reader_list = smart_card_readers.raw.decode().split("\x00")
smart_card_reader_list = [entry for entry in smart_card_reader_list if entry.startswith("SCM")]
print(f"List of Smart Card Readers: {smart_card_reader_list}")


# Load Smart Card Reader DLL
mcscm_dll = ctypes.WinDLL("C:\\Windows\\System32\\MCSCM.dll")  # NOTE: Only works with MCSCM.dll from TEMPOMES driver installer 


for smart_card_reader_name in smart_card_reader_list:

    # Initialize Smart Card Reader with M-CARD API
    reader_name = ctypes.c_char_p(smart_card_reader_name.encode('utf-8'))
    phMCardContext = ctypes.c_int(0)
    pdwDllVersion = ctypes.c_uint32(0)

    result = mcscm_dll.MCardInitialize(phContext, reader_name, ctypes.byref(phMCardContext), ctypes.byref(pdwDllVersion))
    print(f"MCSCM.dll Response to Initializing Smart Card Readers Was: {convert_to_error_code(result)}")


    # Connect to Smart Card
    dwConnectMode = ctypes.c_int(0)
    byCardType = ctypes.c_int(8)
    phMCard = ctypes.c_int(0)

    result = mcscm_dll.MCardConnect(phMCardContext, dwConnectMode, byCardType, ctypes.byref(phMCard))
    print(f"MCSCM.dll Response to Connecting to Smart Card Reader Was: {convert_to_error_code(result)}")


    # Read from SMart Card
    bMemZone = ctypes.c_int(0)
    dwOffset = ctypes.c_int(0)
    pbReadBuffer = (ctypes.c_ubyte * 200)(0)
    pbReadLen = ctypes.c_int(100)

    result = mcscm_dll.MCardReadMemory(phMCard, bMemZone, dwOffset, ctypes.byref(pbReadBuffer), ctypes.byref(pbReadLen))
    print(f"MCSCM.dll Response to Reading from Smart Card Reader Was: {convert_to_error_code(result)}")

    data = ""
    for character in pbReadBuffer:

        if character < 255:
            data = data + chr(character)

    data = data.split("\x1f")[1:-1]  # take care of leading and trailing boundary values


    # Parse data
    smart_card_info = {"First Name": "",
                       "Last Name": "",
                       "MI": "",
                       "User ID": "",
                       "Alt User ID": "",
                       "Index": "",
                       "Employee ID": ""
                       }

    smart_card_info["First Name"] = data[0] if not data[0] == " " else "None"
    smart_card_info["Last Name"] = data[1] if not data[1] == " " else "None"
    smart_card_info["MI"] = data[2] if not data[2] == " " else "None"
    smart_card_info["User ID"] = data[3] if not data[3] == " " else "None"
    smart_card_info["Alt User ID"] = data[4] if not data[4] == " " else "None"
    smart_card_info["Index"] = data[5] if not data[5] == " " else "None"
    smart_card_info["Employee ID"] = data[6] if not data[6] == " " else "None"

    # Print out data to console
    print("\n")
    print(smart_card_reader_name)
    for key, value in smart_card_info.items():
        smart_card_field_info = f"{key}: {value}"
        print(smart_card_field_info)
    print("\n")


    # Disconnect from smart card
    dwDisposition = ctypes.c_int(0)
    result = mcscm_dll.MCardDisconnect(phMCard, dwDisposition)
    print(f"MCSCM.dll Response of Disconnecting from Smart Card Reader Was: {convert_to_error_code(result)}")


    # Shut down smart card reader
    result = mcscm_dll.MCardShutdown(phMCardContext, dwDisposition)
    print(f"MCSCM.dll Response of Shutting Donw the Smart Card Reader Was: {convert_to_error_code(result)}")

I am trying to use javax.smartcardio to try and act as the replacement for c_types, but is proving to be more difficult than expected.

From what I've found in the forum, trying to integrate a .dll is difficult to do, which is why I have been trying to find a workaround.