3

an application I am working on requires to detect, as quick as possible (in 500 ms maximum), that a card is removed from the field.

Here is what I did to test the time needed to detect that absence of the card:

public static long timeToGetCardAbsent(int version) throws CardException{
    TerminalFactory factory = TerminalFactory.getDefault();

    CardTerminals terminalList = factory.terminals();
    CardTerminal ct = terminalList.list().get(0);

    long connectTime = 0, disconnectTime = 0;

    ct.waitForCardPresent(0);
    connectTime = new Date().getTime();

    ct.waitForCardAbsent(0);
    disconnectTime = new Date().getTime();

    return disconnectTime - connectTime;
}

When the program is running, I tap a (DESFire) contactless card on the reader and remove it immediatly.

Here are the outputs:

1437
1437
1438
1437
1422

I means that the reader (or the program?) needs almost 1.5 seconds to detect that the card is absent, which too long time for me.

Is there a way to speed up this detection? I am currently using javax.smartcardio, would I get better results with another library? I actually don't know what else I could use, do you have leads?

Thanks, GChabot

GChabot
  • 143
  • 2
  • 9
  • Have you tried polling that method with a very short waiting time? It could poll internally with a timeframe of about 1.4 seconds or so. You may want to put that in a separate thread if it works later on. – Maarten Bodewes Aug 01 '12 at 21:11
  • Your scenario is a bit untypical in the respect, that you do nothing with the card. I would assume, that removal detection is faster, as soon as you establish a connection with the card. I would be surprised, if a factor of 3 can be achieved by using another library; more likely another reader [brand] may help. – guidot Aug 02 '12 at 06:36
  • @owlstead: I just tried with 222 ms and what I get (I am looping to get several results) is `234 219 219 219 219 234 78`. And if you add all these numbers, you will get 1422, which means that the time to detect the absence of the card is still the same, the only difference is that when the 222 ms timeout is reached, the program behaves as if a new card was detected. – GChabot Aug 02 '12 at 09:55
  • @guidot: I tried another way to test the time to detect the absence of the card by looping on the `ct.connect("*");` function and catching errors when the card is not accessible. Here is what I did : `int state = 0; while(true){ boolean cardPresent = false; try{ ct.connect("*"); cardPresent = true; } catch(Exception e) {} if(state == 0 && cardPresent){ connectTime = new Date().getTime(); state = 1; } if(state == 1 && !cardPresent){ disconnectTime = new Date().getTime(); break; } }` But I get the exact same results. – GChabot Aug 02 '12 at 09:58
  • I am now trying another reader: the Skyetek's SkyeModule M4 (I was using the SCL011 from SCM Microsystems, Inc.). This reader does not provide PC/SC support but a C API. A test program comes with this reader and seems to detect the absence of the card much quicker. But I need a reader that comes in a case as it is to be distributed to clients so I guess I will have to look for another (PC/SC?) reader. – GChabot Aug 02 '12 at 10:09
  • In general the C libs that come with a reader would be more suitable for such a thing yes. Unfortunately developing for them is much harder as well, and it is brand specific... It seems though that you have little choice - or maybe other PCSC readers would behave better. 1.4s seems excessive to me. – Maarten Bodewes Aug 02 '12 at 11:08
  • OK, see my answer. It's more likely that PCSC is the culprit. Could you try and post the versions of your firmware, driver, PCSC implementation and OS? – Maarten Bodewes Aug 02 '12 at 21:54
  • OS: Microsoft Windows XP, Professionnel, Version 2002, Service Pack 3 (French version). winscard.dll version: 5.1.2600.5512 (xpsp.080413-2113). About SCL011 Generic Contacless Reader (in device manager): driver provider: SCM Microsystems Inc.; driver date: 11/01/2011; driver version: 5.9.0.1; Digital signature: Microsoft Windows Hardware Compatibility Publisher; I also have this "software version": 01.12. The Java library is javax.smartcardio from Java 1.7 (jre7). That's all I can think of now but please ask me for more if needed. – GChabot Aug 03 '12 at 08:36
  • [Here is more information coming from a program that came with the SCM's SCL011 reader](http://img11.hostingpics.net/pics/837786SCMInstallationCheckTool.gif) – GChabot Aug 03 '12 at 09:42

2 Answers2

1

I actually managed to improve the detection time a lot today. I was looking at that web page from "NFC Wizard" and noticed that they were very fast at detecting my card removal. This javascript web page communicates with the reader through a Java applet, so it really uses nothing more than I have.

SpringCard, the creators of NFC Wizard, actually provides complete documentation and even source code for a similar application at that page, under Other resources > Java and "SpringCard PC/SC SDK (ZIP archive)".

While browsing their code, I noticed that after performing operations on the card, the use the card.disconnect(false); function (I had tried to use card.disconnect(true); but had the same results as before...bad luck).

So here is now what I do :

import java.util.Date;
import javax.smartcardio.*;

public class NewMethod {
    private long connectTime = -1;
    private long disconnectTime = -1;

    private TerminalFactory factory;
    private CardTerminals terminalList;
    private CardTerminal ct;

    public NewMethod() throws CardException{
        factory = TerminalFactory.getDefault();

        terminalList = factory.terminals();
        ct = terminalList.list().get(0);
    }

    public long waitForCardPresent(){
        try {
            ct.waitForCardPresent(0);
        } catch (CardException e) { }
        return new Date().getTime();
    }

    public long waitForCardAbsent(){
        while(true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e1) { }

            try{
                ct.connect("*").disconnect(false);
            }
            catch(Exception e) {
                return new Date().getTime();
            }
        }
    }

    public void run(){
        while(true){
            connectTime = waitForCardPresent();
            disconnectTime = waitForCardAbsent();
            System.out.println((disconnectTime-connectTime));
        }
    }

    public static void main(String[] args){
        NewMethod nm;
        try {
            nm = new NewMethod();
            nm.run();
        } catch (CardException e) {
            e.printStackTrace();
        }
    }
}

(The thread part is optional but I got the same results with or without it so I preferred to save a bit of processor consumption)

Here are the times I got with the threaded version: 531, 437, 656, 657, 735, 657, 547, 844, 15, 766, 859, 563, 765, 562, 422, 437, 563, 562, 562, 672, 672, 16, 547, 546, 672, 15, 344 and here with the unthreaded version: 984, 547, 796, 656, 796, 718, 656, 812, 625, 781, 813, 547, 797, 532, 407, 609, 719, 328, 469, 328, 0, 546, 625, 0, 843, 703

We may notice that the results are quite unstable (and quite better with the threaded version actually), this might come from the way I tap the card against the reader but I believe this is not the only reason.

It looks good enough for me now. I just hope I won't get a too great variability when I will actually use it on my application.

GChabot
  • 143
  • 2
  • 9
  • Interesting hack for sure. If it works, it works, but be sure to test each separate configuration. If you can control the PCSC layer on the host I would try that because there should be a lot of room for improvement. – Maarten Bodewes Aug 04 '12 at 09:24
  • I will actually use this function in a Java applet, so it might be difficult to control the PCSC layer on the host. Or maybe it is possible to join a DLL file in the Java applet? Anyway, for sure, I will try this on as much configurations as I can. Thanks for the help. – GChabot Aug 06 '12 at 08:20
  • It is possible to install a DLL from a signed applet, but I would strongly urge you not to go in that direction. – Maarten Bodewes Aug 06 '12 at 15:02
0

I've tested a bit on Linux, and in Linux, the default PCSC deamon is polling the driver each 400-500ms. Unstable drivers seem to remove this polling and use a different method, if the PCSC Lite information that I found is correct.

The Java method seems to return almost instantly, so that's not likely to be the culprit. Try and update your PCSC implementation, firmware and drivers to the latest version. If that does not work you've got no choice to work around it.

That answer did cost me an installation of PCSC on Linux + SCM SDI010 driver installation and the test of 3 firmware's. But I wanted the info myself anyway. I'll update the answer if I get a newer version of PCSC lite to work.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Great thanks for your help! I try to use (what I think to be) a newer version of PC/SC by downloading a version of WinSCard.dll found [here](http://www.dll-files.com/dllindex/dll-files.shtml?winscard). But with that version, my CardTerminal isn't detected anymore. I also tried to update my driver through Windows' device manager but it cannot find any newer one. Should I try to use PCSC-lite on Windows? Is it even possible? – GChabot Aug 03 '12 at 08:59
  • I just tried using C# and ["pcsc-sharp", the first wrapper of this entry of Ludovic Rousseau blog](http://ludovicrousseau.blogspot.no/2010/11/pcsc-sample-in-c.html). I basically modified the _Hello World_ example: I try to connect to the card, and if an exception is raised, it means that the card is not present. I loop on that function and record when the time the card is detected. It turned out that the results were even worst: an average of 2 seconds, with values from 800 ms to more than 3 seconds. – GChabot Aug 03 '12 at 11:52
  • PCSC lite is the windows smartcard interface implemented fox linux, I would not expect that it us easy to get it working in Windows, although that's just a guess. – Maarten Bodewes Aug 06 '12 at 15:04