Search code examples
c++serial-portrfidmifaresmartcard-reader

How to connect 2 RFID Reader simultaneously in C++?


I have 2 RFID readers.

  • Reader 1: port=com4 and baud=9600
  • Reader 2: port=com9 and baud=9600

I want to connect 2 RFID readers simultaneously. However, even if I instantiate both readers in my code, I only manage to access one of the two readers.

I do the following:

  1. MifareOne.CPP

    MifareOne::MifareOne()
    {
        LoadDll();
    }
    
    MifareOne::~MifareOne()
    {
        CloseComm();
        CloseDll();
    }
    
    bool IsLoadDLL = false;
    bool MifareOne::LoadDll()
    {
        if (IsLoadDLL)
            return true;
    
        // TODO: Add extra initialization here
        TCHAR szBuf[MAX_PATH];
        GetModuleFileName(NULL, (LPTSTR)szBuf, MAX_PATH);
    
        sprintf(szBuf, "../../../CardReader\\MasterRD.dll");
        m_hInstMaster = LoadLibrary(_T(szBuf));
    
    
        if (m_hInstMaster)
        {
            IsLoadDLL = true;
            (FARPROC&)lib_ver = GetProcAddress(m_hInstMaster, _T("lib_ver"));
            (FARPROC&)des_encrypt = GetProcAddress(m_hInstMaster, _T("des_encrypt"));
            (FARPROC&)des_decrypt = GetProcAddress(m_hInstMaster, _T("des_decrypt"));
            (FARPROC&)rf_init_com = GetProcAddress(m_hInstMaster, _T("rf_init_com"));
            (FARPROC&)rf_init_device_number = GetProcAddress(m_hInstMaster, _T("rf_init_device_number"));
            (FARPROC&)rf_get_device_number = GetProcAddress(m_hInstMaster, _T("rf_get_device_number"));
            (FARPROC&)rf_get_model = GetProcAddress(m_hInstMaster, _T("rf_get_model"));
            (FARPROC&)rf_get_snr = GetProcAddress(m_hInstMaster, _T("rf_get_snr"));
            (FARPROC&)rf_beep = GetProcAddress(m_hInstMaster, _T("rf_beep"));
            (FARPROC&)rf_init_sam = GetProcAddress(m_hInstMaster, _T("rf_init_sam"));
            (FARPROC&)rf_sam_rst = GetProcAddress(m_hInstMaster, _T("rf_sam_rst"));
            (FARPROC&)rf_sam_cos = GetProcAddress(m_hInstMaster, _T("rf_sam_cos"));
            (FARPROC&)rf_init_type = GetProcAddress(m_hInstMaster, _T("rf_init_type"));
            (FARPROC&)rf_antenna_sta = GetProcAddress(m_hInstMaster, _T("rf_antenna_sta"));
            (FARPROC&)rf_request = GetProcAddress(m_hInstMaster, _T("rf_request"));
            (FARPROC&)rf_anticoll = GetProcAddress(m_hInstMaster, _T("rf_anticoll"));
            (FARPROC&)rf_select = GetProcAddress(m_hInstMaster, _T("rf_select"));
            (FARPROC&)rf_halt = GetProcAddress(m_hInstMaster, _T("rf_halt"));
            (FARPROC&)rf_download_key = GetProcAddress(m_hInstMaster, _T("rf_download_key"));
            (FARPROC&)rf_M1_authentication1 = GetProcAddress(m_hInstMaster, _T("rf_M1_authentication1"));
            (FARPROC&)rf_M1_authentication2 = GetProcAddress(m_hInstMaster, _T("rf_M1_authentication2"));
            (FARPROC&)rf_M1_read = GetProcAddress(m_hInstMaster, _T("rf_M1_read"));
            (FARPROC&)rf_M1_write = GetProcAddress(m_hInstMaster, _T("rf_M1_write"));
            (FARPROC&)rf_M1_initval = GetProcAddress(m_hInstMaster, _T("rf_M1_initval"));
            (FARPROC&)rf_M1_readval = GetProcAddress(m_hInstMaster, _T("rf_M1_readval"));
            (FARPROC&)rf_M1_decrement = GetProcAddress(m_hInstMaster, _T("rf_M1_decrement"));
            (FARPROC&)rf_M1_increment = GetProcAddress(m_hInstMaster, _T("rf_M1_increment"));
            (FARPROC&)rf_M1_restore = GetProcAddress(m_hInstMaster, _T("rf_M1_restore"));
            (FARPROC&)rf_M1_transfer = GetProcAddress(m_hInstMaster, _T("rf_M1_transfer"));
            (FARPROC&)rf_typea_rst = GetProcAddress(m_hInstMaster, _T("rf_typea_rst"));
            (FARPROC&)rf_cos_command = GetProcAddress(m_hInstMaster, _T("rf_cos_command"));
            (FARPROC&)rf_atqb = GetProcAddress(m_hInstMaster, _T("rf_atqb"));
            (FARPROC&)rf_attrib = GetProcAddress(m_hInstMaster, _T("rf_attrib"));
            (FARPROC&)rf_typeb_cos = GetProcAddress(m_hInstMaster, _T("rf_typeb_cos"));
            (FARPROC&)rf_hltb = GetProcAddress(m_hInstMaster, _T("rf_hltb"));
            (FARPROC&)rf_at020_check = GetProcAddress(m_hInstMaster, _T("rf_at020_check"));
            (FARPROC&)rf_at020_read = GetProcAddress(m_hInstMaster, _T("rf_at020_read"));
            (FARPROC&)rf_at020_write = GetProcAddress(m_hInstMaster, _T("rf_at020_write"));
            (FARPROC&)rf_at020_lock = GetProcAddress(m_hInstMaster, _T("rf_at020_lock"));
            (FARPROC&)rf_at020_count = GetProcAddress(m_hInstMaster, _T("rf_at020_count"));
            (FARPROC&)rf_at020_deselect = GetProcAddress(m_hInstMaster, _T("rf_at020_deselect"));
            (FARPROC&)rf_light = GetProcAddress(m_hInstMaster, _T("rf_light"));
            (FARPROC&)rf_ClosePort = GetProcAddress(m_hInstMaster, _T("rf_ClosePort"));
            (FARPROC&)rf_GetErrorMessage = GetProcAddress(m_hInstMaster, _T("rf_GetErrorMessage"));
    
            if (NULL == lib_ver ||
                NULL == des_encrypt ||
                NULL == des_decrypt ||
                NULL == rf_init_com ||
                NULL == rf_init_device_number ||
                NULL == rf_get_device_number ||
                NULL == rf_get_model ||
                NULL == rf_beep ||
                NULL == rf_init_sam ||
                NULL == rf_sam_rst ||
                NULL == rf_sam_cos ||
                NULL == rf_init_type ||
                NULL == rf_antenna_sta ||
                NULL == rf_request ||
                NULL == rf_anticoll ||
                NULL == rf_select ||
                NULL == rf_halt ||
                NULL == rf_download_key ||
                NULL == rf_M1_authentication1 ||
                NULL == rf_M1_authentication2 ||
                NULL == rf_M1_read ||
                NULL == rf_M1_write ||
                NULL == rf_M1_initval ||
                NULL == rf_M1_readval ||
                NULL == rf_M1_decrement ||
                NULL == rf_M1_increment ||
                NULL == rf_M1_restore ||
                NULL == rf_M1_transfer ||
                NULL == rf_typea_rst ||
                NULL == rf_cos_command ||
                NULL == rf_atqb ||
                NULL == rf_attrib ||
                NULL == rf_typeb_cos ||
                NULL == rf_hltb ||
                NULL == rf_at020_check ||
                NULL == rf_at020_read ||
                NULL == rf_at020_write ||
                NULL == rf_at020_lock ||
                NULL == rf_at020_count ||
                NULL == rf_at020_deselect ||
                NULL == rf_light ||
                NULL == rf_ClosePort ||
                NULL == rf_GetErrorMessage)
            {
                return false;
            }
        }
        else
        {
            int err = GetLastError();
            return false;
        }
    
        return true;
    }
    
    bool MifareOne::CloseDll()
    {
        if(m_hInstMaster)
        {
            FreeLibrary(m_hInstMaster);
            lib_ver = NULL;
            des_encrypt = NULL;
            des_decrypt = NULL;
            rf_init_com = NULL;
            rf_init_device_number = NULL;
            rf_get_device_number = NULL;
            rf_get_model = NULL;
            rf_beep = NULL;
            rf_init_sam = NULL;
            rf_sam_rst = NULL;
            rf_sam_cos = NULL;
            rf_init_type = NULL;
            rf_antenna_sta = NULL;
            rf_request = NULL;
            rf_anticoll = NULL;
            rf_select = NULL;
            rf_halt = NULL;
            rf_download_key = NULL;
            rf_M1_authentication1 = NULL;
            rf_M1_authentication2 = NULL;
            rf_M1_read = NULL;
            rf_M1_write = NULL;
            rf_M1_initval = NULL;
            rf_M1_readval = NULL;
            rf_M1_decrement = NULL;
            rf_M1_increment = NULL;
            rf_M1_restore = NULL;
            rf_M1_transfer = NULL;
            rf_typea_rst = NULL;
            rf_cos_command = NULL;
            rf_atqb = NULL;
            rf_attrib = NULL;
            rf_typeb_cos = NULL;
            rf_hltb = NULL;
            rf_at020_check = NULL;
            rf_at020_read = NULL;
            rf_at020_write = NULL;
            rf_at020_lock = NULL;
            rf_at020_count = NULL;
            rf_at020_deselect = NULL;
            rf_light = NULL;
            rf_ClosePort = NULL;
            rf_GetErrorMessage = NULL;
            m_hInstMaster = NULL;
            return true;
        }
        return false;
    }
    
    bool MifareOne::OpenComm(int com, int baud)
    {
        //save port and baud
        mCommPort = com;
        mBandRate = baud;
    
        //open port
        int state = 1;
        state = rf_init_com(com, baud);
    
        if (state != LIB_SUCCESS){
            rf_ClosePort();
            return false;
        }
    
        return true;  // return TRUE  unless you set the focus to a control
    }
    
    bool IsCloseComm = false;
    void MifareOne::CloseComm()
    {
        if (IsCloseComm)
            return;
    
        rf_ClosePort();
        IsCloseComm = true;
    }
    
    int MifareOne::Write(unsigned char* strData)
    {
        WORD icdev = 0x0000;
        unsigned char mode = 0x60; // key A
        unsigned char secnr = '\x1';
        int state;
        unsigned char strKey[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 };
        int nSel = 1;   
    
        state = rf_M1_authentication2(icdev, mode, (secnr / 4) * 4, strKey);
        if (state){
            return -1;
        }
    
        unsigned char strEncryptData[MAX_RF_BUFFER];
        state = Encrypt(strEncryptData, strData, (unsigned char*)Encrypt_Key);
        if (state){
            return -1;
        }   
    
        state = rf_M1_write(icdev, secnr, strEncryptData);
        if (state){
            return -1;
        }
    
        return 1;
    }
    
  2. Main.CPP

    int main(int argc, const char* argv[])
    {
        MifareOne cardReader1;
        MifareOne cardReader2;
    
        cardReader1.OpenComm(4, 9600);
        cardReader2.OpenComm(9, 9600);
    
        cardReader1.Write((unsigned char*) "testing");   // Not work
        cardReader2.Request((unsigned char*) "testing"); // Work fine
    }
    

Solution

  • Your problem is that the DLL you're using to access the RFID device only supports accessing one device at a time. Each of two calls that you make to MifareOne::OpenComm method call the same rf_init_com function in the same MasterRD.dll. The rf_init_com method doesn't return any sort of handle that you can use to distinguish between multiple connections so there's no way for your MifareOne::Write method to tell the DLL which of the two connections you want to use.

    Given that the DLL doesn't allow you to open more than one device at a time you only two possible workarounds. The first to use the DLL in two different processes, each process communicating with a different RFID device. In this case DLL will have a separate internal state in each process allowing you to use it to open a different device in each process. You'll then have to use one of Windows's many interprocess communication methods to allow these two processes to coordinate with each other or a master process.

    The second is to talk to the RFID device directly through the serial port. Windows lets you open multiple serial devices open in the same process at the same time. Using this workaround means that you'll have to handle all the low level protocol details of talking to the device yourself. The same low-level details the DLL you're using is meant to insulate you from. You'll also probably either to use asynchronous I/O or multiple threads to avoid deadlocks while reading and writing from the two devices.