0

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
    }
    
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
Van Duoc
  • 65
  • 1
  • 8
  • 1
    It is operating system (and possibly device and library) specific. So please tag your question appropriately. Standard C++11 don't know about RFID. – Basile Starynkevitch Aug 20 '14 at 10:15
  • 1
    "simultaneously" literally means at the same time. So "connect 2 readers simultaneously" contradicts " connect 1 reader at the same time" – MSalters Aug 20 '14 at 10:46
  • What is "connecting an RFID reader"? What should happen that you call it "simultaneously"? – harper Aug 20 '14 at 11:59
  • I'm using computer to connect 2 RFID reader via COM port. If I connect only one RFID reader then it work fine (read and write data is OK). If I connect 2 RFID reader then the card reader which is connected later work fine! – Van Duoc Aug 20 '14 at 12:44
  • 1
    What is the programming problem? Can we get an idea what you have tried, what is your question? A lot of code which give us no idea of the real underlaying problem... – Klaus Aug 20 '14 at 13:42
  • I think what the questioner means is that if he physically connects two readers to his computer, only one reader can be accessed by his software (the one that was plugged in second). – IanPudney Aug 20 '14 at 13:53

3 Answers3

1

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.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
0

I can think of three possibilities.

First is that you are testing one reader with the Request() method, and the other with the Write() method. It may be that Write() is incorrect. Try using Request() for both your readers and see what happens.

Second is that you have the wrong COM ports. Open your Device Manager and determine which ports your devices are operating on. Verify that you are using the right ports after plugging in both of them.

Third is that another program, perhaps an older version of your software, is using the COM port. Try restarting your computer or otherwise checking if the port is in use.

IanPudney
  • 5,941
  • 1
  • 24
  • 39
0

The reader DLL's interface looks as if only one reader is supported at a time. A clear indication for this is that the API functions do not use a handle with which they could keep track of two simultaneous sessions.

So, for instance,

cardReader1.OpenComm(4, 9600);

causes the following API call:

state = rf_init_com(4, 9600);

where state is 0 upon success. Consequently there is no "handle" that could be used to keep track of this specific rf_init_com call.

So if you next use

cardReader2.OpenComm(9, 9600);

to open the second reader's port. This will cause the following API call:

state = rf_init_com(9, 9600);

As the DLL does not keep track of multiple connections two thinkgs could now happen:

  1. The first connection is dropped in favor of the second one, or
  2. the second connection request will be ignored as there is still an open connection with the first reader.

So once, you used OpenComm for both MifareOne objects, calls on both objects will either go to the second (case 1) or to the first (case 2) reader. Specifically, if you look at the API call that is executed as a consequence of

cardReader1.Write((unsigned char*) "testing");

and of

cardReader2.Write((unsigned char*) "testing");

You will see that both methods will cause the same API calls:

 state = rf_M1_authentication2(icdev, mode, (secnr / 4) * 4, strKey);
 state = rf_M1_write(icdev, secnr, strEncryptData);

So the DLL can impossibly distinguish between the two readers.

Thus, in my opinion, the DLL was not designed to be used with multiple readers.

Michael Roland
  • 39,663
  • 10
  • 99
  • 206