In my original design, the Reader created the Card objects.
Depending on the card standard, it would create the appropriate object.
But now, I want to add a special card, the Infineon Security2Go card. It's a ISO14443 card, but it runs a custom application.
There are (as always) several way to model this.
In this post, I choose to create a new class that inherits from the ClassISO14443, and add behaviour for the Infineon card.
Side bar |
---|
In a later phase I think I want to change this - again. In stead of inheriting and adding methods to support the card's application , I think about building a different set of classes that represent the application. And leave the Card tree for industry standard cards... open for discussion. |
What I learned while extending the card class for the Infineon card, I'd also had to extend the Reader class to.
To make it recognise Infineon cards and learn how to create an object of the custom class for them.
But the Reader doesn't change. It uses the same protocols, functions, .... . So that's unfortunate, that it has this binding with any possible card.
The Reader class was intended to deal with the NFC hardware. So I should not contaminate it with non-reader related tasks.
So I moved the createCard() family of functions out of the Reader family, and moved it (for now) to the Factory family.
From:
Card* UfrReader::getCard() { //... // if DL_MIFARE_MINI, the ID is to be ignored. // Create an ISO14443_4 card Card *card = NULL; if (lpucSak == DL_MIFARE_MINI) { card = new CardISO14443(this, lpucSak, id, lpucUidSize); } else { std::copy(std::begin(aucUid), std::end(aucUid), id.begin()); card = new Card(this, lpucSak, id, lpucUidSize); } return card; }
To:
Card* UfrFactory::getCard(Reader *reader) { //... // if DL_MIFARE_MINI, the ID is to be ignored. // Create an ISO14443_4 card Card *card = NULL; if (lpucSak == DL_MIFARE_MINI) { card = new CardISO14443(reader, lpucSak, id, lpucUidSize); } else { std::copy(std::begin(aucUid), std::end(aucUid), id.begin()); card = new Card(reader, lpucSak, id, lpucUidSize); } return card; }
So it's out of the Reader family. That one can concentrate on standard functionality again.
For programs that need to work with an Infineon card, I created a dedicated factory:
class S2GoFactory: public UfrFactory { public: static CardS2Go * getCard(Reader *reader) { //... CardS2Go *card = NULL; card = new CardS2Go(reader, lpucSak, id, lpucUidSize); return card; } };
Side bar |
---|
Future design: Having worked with the framework for a while now, I am thinking to loosen several bounds:
|
As with the previous posts, the current version of the app is attached. It checks the ID of a Security2Go card.
int main() { Reader *reader = NULL; try { reader = S2GoFactory::getReader(); while (!reader->hasCard()) { usleep(500); } CardS2Go *crd = S2GoFactory::getCard(reader); std::cout << "this is an ISO14443 capable card" << std::endl; crd->setISO14443_4(); crd->selectApp(); crd->unsetISO14443_4(); S2GoFactory::releaseCard(crd, reader); crd = NULL; } catch (const UrfException &e) { std::cerr << e.what() << ": 0x" << std::hex << e.getError() << std::dec << std::endl; } S2GoFactory::releaseReader(reader); reader = NULL; return 0; }
Related Blog |
---|
Blockchain - Talk Directly to the Infineon 2Go Smart Cards API |
NFC Card Reader Protocol of Digital Logic µFR - part 0: intent |
µFR NFC Card Reader - part 1: first C program for Linux (RPi, BB, ...) |
µFR NFC Card Reader - part 2: first C++ program |
µFR NFC Card Reader - part 3: C++ Class to handle ISO14443 / APDU cards |
µFR NFC Card Reader - part 4: first meaningful ISO14443 / APDU conversation |
µFR NFC Card Reader - part 5: refactor, look back at initial design |