Qt Webkit with Proximity Smart Card (RFID) on Freescale i.MX51

Published on March 4, 2011

Archived Notice

This article has been archived and may contain broken links, photos and out-of-date information. If you have any questions, please Contact Us.

In the previous two blog posts, we described how you can integrate a mag stripe reader and barcode scanner into the
Qt Webkit framework by using the Qt Webkit Bridge.

In this post, we'll build upon those two examples by integrating a proximity smart card (RFID) reader, which is
somewhat more complicated because it allows sending commands as well as receiving responses.

We'll use the very nice SL015B reader from Stronglink for this example, but the approach should apply to many applications which require bi-directional communications from web applications.
In order to follow the details, you'll want to grab a copy of the User's manual.

Before delving into the code, we should look closely at some of the key characteristics of the RFID reader and cards. I know that the cards supported by the Stronglink device aren't actually RFID cards, but proximity smart cards, but RFID is much easier to type (and say). I also understand that the Stronglink device is a reader/writer, but I'll refer to it as a reader for brevity.

Looking at the Stronglink manual, it's clear that all communication is of the form request->response. All commands are initiated by the host (in this case, our Nitrogen board. Each response from the reader contains a reference to the command along with the status and optional data.

Since our target application environment is the killer web-app, one of the primary design criteria will be how to handle the asynchronous nature of request from the app. When we send a command to the reader, we can't just block waiting for a response or that fancy animation our app is doing will visibly choke. Furthermore, many operations we'd like to perform on a card will require multiple message exchanges. To top things off, these are proximity smart cards and can be removed or presented in the middle of an operation, so we'd like to be able to handle a multi-message operation gracefully.

Let's examine a couple of mechanisms we might use. As a test case, we'll use a simple example of a two message exchange:

  1. Login to a sector (command 0x02)
  2. Read block 0

In each of the examples, I'll separate out the command code and data on the transmit side and the response code from optional data on the receive side. I'll also assume that the rfid object will handle checksum calculation and inserting the message length.

The simplest implementation: it's all up to the app

The simplest implementation is to simply leave everything up to the application and expose a send() routine and a receive() handler.

[sourcecode language="plain"]rfid.receive = function(responseCode, data){<br /> console.log("rfid rx:"+responseCode.toString(16)+":"+escape(data)+"n");<br /> // switch based on state of communication?<br /> }<br /> // send sector 0, key A, key<br /> rfid.send(0x02, "x00xAAx01x02x03x04x05x06");<br /> [/sourcecode]

In this case, the send method could be directly implemented in C++ and the single receive routine could be connected to a signal (i.e. it could be a slot).

I'm not going to provide pseudo-code for the response handler because this interface doesn't seem to scale very well. If you try to use the handler for application code, you'll likely end up with a mess. This approach could be used as the basis for a higher-level interface, but that would simply be moving the issue from C++ to Javascript.

If you consider the need to poll for card presentation and removal, it doesn't seem that a garbage-collected Javascript is the right place to do this.

Keeping it together

A simpler interface for the application is probably something like this:

    rfid.send( 0x02, "x00xAAx01x02x03x04x05x06",
                   function(responseCode, responseData){
                         console.log( "received response: "+responseCode.toString(16)+":"+responseData);
                   }
    );

That is, for each transmission to the card, we define a anonymous handler function. This will allow apps to keep the handler close to its' origin and improve overall readability.

It still might be a problem though.

If you extend this to the sector login + read block example, you'd naturally end up with something like this:

    rfid.send( 0x02, "x00xAAx01x02x03x04x05x06",
                   function(responseCode, responseData){
                         console.log( "received login response: "+responseCode.toString(16)+":"+responseData);
                         if (0 === responseCode) {
                                  rfid.send (0x03, "x00", function(responseCode, responseData){
                                  console.log( "received block read response: "+responseCode.toString(16)+":"+responseData);
                        });
                    }
    );

This might not be too bad for a single block read, but if you scatter many of these around your application, or if you need to read and write multiple blocks, you'll probably want something different.

Starting from the top

Let's back up a bit and see where we really want to be. Ignoring the details of the actual card reader, we probably want to do something like this in our application:

rfid.read_block(
      blockNum,
      function(blockData){
            console.log("read block"+blockNum.toString(16)+":"+escape(blockData));
      },
      function(errorMsg){
            console.log("error "+errorMsg+" reading block"+blockNum.toString(16));
      }
);

That is, provide a single high-level operation that occurs atomically or not at all. Because of the nature of the RFID connection, we can't guarantee atomicity, but we can support a single success handler and a single failure handler through some mixture of C++ and Javascript. For our simple example, the response code from the reader could simply invoke either the success or error function based on the returned status. Because the Stronglink reader does a nice job of always using 0 to indicate success, this works pretty well.

We could define the read_block routine in Javascript and keep track of the outstanding requests in some form of list.
We could even do all of this in that single simple handler we described at the outset.

Our simple example is probably too simple to be generalized, though. If you think through what would be necessary in a more complex example like a multi-block read or a multi-block write, some things become clear:

  1. A request list is needed,
  2. Some of the responses may contain optional data,
  3. We'll need to coordinate these requests with polls to see if the card is still present.

The third item in the list is the clincher for me. I'd really like to keep device polling in the C++ layer to allow an application which only needs the serial number of a card to something like this:

rfid.cardPresent.connect(function(serialNum,cardType){ console.log("card present: "+escape(serialNum)+":"+cardType); }); rfid.cardRemoved.connect(function(){ console.log("card removed"); });

If the C++ layer is doing the polling for card presentation and removal, it really needs to know whether the application is in the middle of a multi-message transaction.

And by that reasoning, the C++ layer should have a list of requests.

A design takes shape

If you've followed me this far, there's not too much further to go before digging into the code.

  1. Native (C++) send routine will accept an array of requests,
  2. Native (C++) will provide four signals:
    1. cardPresent. This signal will be fired each time a card is presented and will supply the serial number and card type.
    2. cardRemoved. This signal will be fired each time a card is removed.
    3. success. This signal will be generated once after the last message in a transaction succeeds. Data returned from each of the messages in a transaction will be accumulated in an array of the same length as the request array for processing on the Javascript side.
    4. failure. This signal will be generated when any message in a transaction fails. If data was gathered during preceding messages in the transaction, it will be returned to the Javascript code for processing.

    Either the success or failure signal will be generated once for each request made to the send method.

  3. If a transaction is in progress when a card removal event occurs, the failure signal will be emitted and the cardRemoved signal will be emitted in that order.
  4. If send is called when no card is present, the failure signal will be generated immediately.
  5. A convenience method isPresent will be made available.

An implementation takes shape

Alright, this is now done, and I only diverged a bit from the design.

  • Instead of having separate success and failure methods, I implemented a single response() method that is handed a response code and set of zero or more message results.
  • I implemented two forms of send().
    • The first accepts two parameters: a message type (integer command code) and optional data.
    • The second accepts one parameter: an array of objects of the form {code:0x01, data:"x01x02x03"}. This form will send each of the pieces until something fails or the response to the last message is parsed.

This handler code now works:

         rfid.cardPresent.connect(function(serialNum,cardType){
            console.log("card present: "+escape(serialNum)+":"+cardType);
         });
         rfid.cardRemoved.connect(function(){
            console.log("card removed");
         });
         rfid.response.connect(function(result,msgParts){
            console.log("response code: 0x"+result.toString(16));
            try {
               for (var i = 0 ; i < msgParts.length ; i++ ) {
                  var obj = msgParts[i];
                  console.log(i);
                  var rcode = obj.result ;
                  var data = obj.data ;
                  console.log('['+i+']: 0x'+rcode.toString(16)+':'+data);
               }
            } catch(errmsg) {
               console.log( "Error  in response handlern");
            }
            console.log("response received: "+$.toJSON(arguments));
         });

Actually, it doesn't completely work. The $.toJSON() always returns an empty string and I haven't yet pursued why.

Note that the response handler receives a single result code and an array of message objects. Each message object will contain the data returned from the associated piece of the request array.

As a convenience, I introduced a Javascript console to the test browser in this iteration. It turns out that reading from stdin and evaluating a string in the Javascript are incredibly easy in Qt. By using this, I was able to test
the interfaces from the console instead of writing a bunch of HTML scaffolding. The following are some test cases and their output.

Select a card once

The first line is what I typed in to stdin and the remaining lines are the output. The call to send uses two parameters to differentiate it from the array form. The command code is a select card for simplicity:

rfid.send(1,"")
https://10.0.0.1/testrfid.html:23:response code: 0x0
https://10.0.0.1/testrfid.html:27:0
https://10.0.0.1/testrfid.html:30:[0]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:35:response received: {}

Things to note in the output include:

  • Line 27 shows the global result code (0). This is repeated in the single fragment on line 30. It turns out that the global response code will always be the value of the last fragment, but it seems more intuitive to separate it.
  • The JSON output on line 35 is bogus. Why?
  • The data returned in the output is escaped. This is done because I haven't figured out how to push binary data through the Qt Webkit bridge.

Select a card four times

Again, this example uses the select card command for simplicity:

rfid.send([{code:1},{code:1},{code:1},{code:1},{code:1}])
https://10.0.0.1/testrfid.html:23:response code: 0x0
https://10.0.0.1/testrfid.html:27:0
https://10.0.0.1/testrfid.html:30:[0]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:27:1
https://10.0.0.1/testrfid.html:30:[1]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:27:2
https://10.0.0.1/testrfid.html:30:[2]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:27:3
https://10.0.0.1/testrfid.html:30:[3]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:27:4
https://10.0.0.1/testrfid.html:30:[4]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:35:response received: {}

Note that the optional data isn't necessary in this form. It's also possible that I'll want to deprecate the two parameter version because this:

rfid.send(1,'')

Isn't that much clearer than this:

rfid.send([{code:1}]);

Error example

As a final example, here's the output from a three-fragment transaction where the second transaction (a block read request) fails because we haven't logged in to that sector:

rfid.send([{code:1},{code:3,data:"x00x01x02x03"},{code:1}])
https://10.0.0.1/testrfid.html:23:response code: 0xd
https://10.0.0.1/testrfid.html:27:0
https://10.0.0.1/testrfid.html:30:[0]: 0x0:l%CFa%7E%01
https://10.0.0.1/testrfid.html:27:1
https://10.0.0.1/testrfid.html:30:[1]: 0xd:
https://10.0.0.1/testrfid.html:35:response received: {}

Note that the global response code on line 23 shows a value of 0x0d or Not authenticate and that two elements are available in the returned result since only two messages were sent.

This is probably enough for one blog post. We didn't quite get to the ideal block read and block write implementation, but we're not far.

If you made it through this entire blog post, shoot us a note and give some feedback.

The sources are available here.