User Tools

Site Tools


api-how-to-examples

How To

Your project will at least requires the following include files:

#include <logicalaccess/dynlibrary/librarymanager.hpp>
#include <logicalaccess/readerproviders/readerconfiguration.hpp>
#include <logicalaccess/cards/cardprovider.hpp>

Initialize a reader connection

The first step to do for any operation is to initialize the reader communication. The uses of a Reader Configuration object allow you to serialize/unserialize the reader choice in an easy way to reuse it later.

// Reader configuration object to store reader provider and reader unit selection.
boost::shared_ptr<logicalaccess::ReaderConfiguration> readerConfig(new logicalaccess::ReaderConfiguration());
 
// Set PCSC ReaderProvider by calling the Library Manager which will load the function from the corresponding plug-in
readerConfig->setReaderProvider(logicalaccess::LibraryManager::getInstance()->getReaderProvider("PCSC"));
 
// Create the default reader unit. On PC/SC, we will listen on all readers.
readerConfig->setReaderUnit(readerConfig->getReaderProvider()->createReaderUnit());
if (readerConfig->getReaderProvider()->getRPType() == "PCSC" && readerConfig->getReaderProvider()->getReaderList().size() == 0)
{
  std::cerr << "No readers on this system." << std::endl;
  return EXIT_FAILURE;
}
std::cout << readerConfig->getReaderProvider()->getReaderList().size() << " readers on this system." << std::endl;
 
readerConfig->getReaderUnit()->connectToReader();
 
// DO CARD STUFF HERE
// DO CARD STUFF HERE
// DO CARD STUFF HERE
 
readerConfig->getReaderUnit()->disconnectFromReader();

Communicate with a chip

Once connected to the reader, we want to communicate with the chip. We wait a card insertion on the reader, get the associated chip object and we are ready to send command to it.

std::cout << "Waiting 15 seconds for a card insertion..." << std::endl;
if (readerConfig->getReaderUnit()->waitInsertion(15000))
{
       if (readerConfig->getReaderUnit()->connect())
       {
             // Display few chip information
 
             std::cout << "Card inserted on reader \"" << readerConfig->getReaderUnit()->getConnectedName() << "\"." << std::endl;
 
             boost::shared_ptr< LOGICALACCESS::Chip> chip = readerConfig->getReaderUnit()->getSingleChip();
             std::cout << "Card type: " << chip->getCardType() << std::endl;
 
             std::vector<unsigned char> csn = readerConfig->getReaderUnit()->getNumber(chip);
             std::cout << "Card unique manufacturer number : " << logicalaccess::BufferHelper::getHex(csn) << std::endl;
 
             // DO CHIP COMMAND HERE
             // DO CHIP COMMAND HERE
             // DO CHIP COMMAND HERE
 
             readerConfig->getReaderUnit()->disconnect();
       }
 
       std::cout << "Logical automatic card removal in 15 seconds..." << std::endl;
       if (!readerConfig->getReaderUnit()->waitRemoval(15000))
       {
             std::cerr << "Card removal forced." << std::endl;
       }
 
       std::cout << "Card removed." << std::endl;
} 
else
{
       std::cout << "No card inserted." << std::endl;
}

Read/Write data on the chip

Once connected to the chip, you can execute some commands like read and write data for example. A generic layer, available for all memory chips, can be used to set data location (where is the data) and data access information (authentication key).

boost::shared_ptr<logicalaccess::StorageCardService> storage = boost::dynamic_pointer_cast<logicalaccess::StorageCardService>(chip->getService(logicalaccess::CST_STORAGE));
 
boost::shared_ptr<logicalaccess::Location> location;
boost::shared_ptr<logicalaccess::AccessInfo> aiToUse;
boost::shared_ptr<logicalaccess::AccessInfo> aiToWrite;

You should define location and access information according to the targeting chip. See mifare-classic-examples for an example with Mifare Classic.
Then use it:

// Data to write
unsigned char writedata[10];
memset(writedata, 0x00, sizeof(writedata));
writedata[0] = 0x11;       // Doomy value 
writedata[9] = 0xff;       // Doomy value 
 
// Data read
unsigned char readdata[10];
memset(readdata, 0x00, sizeof(readdata));
 
 
// Write data on the specified location with the specified key
storage->writeData(location, aiToUse, aiToWrite, writedata, sizeof(writedata), logicalaccess::CB_DEFAULT);
 
// We read the data on the same location. Remember, the key is now changed.
storage->readData(location, aiToWrite, readdata, sizeof(readdata), logicalaccess::CB_DEFAULT);

Access control chip service

boost::shared_ptr<logicalaccess::Format> format;
 
/* -------------------------------- */
/* Example with Wiegand 26 format   */
/* -------------------------------- */
 
boost::shared_ptr<logicalaccess::Wiegand26Format> w26format(new logicalaccess::Wiegand26Format());
format = w26format;
 
/* -------------------------------- */
/* -------------------------------- */
/* -------------------------------- */
 
boost::shared_ptr<logicalaccess::AccessControlCardService> acService = boost::dynamic_pointer_cast<logicalaccess::AccessControlCardService>(chip->getService(logicalaccess::CST_ACCESS_CONTROL));

Write access control format

/* -------------------------------- */
/* Example with Wiegand 26 format   */
/* -------------------------------- */
 
w26format->setFacilityCode(50);
w26format->setUid(1000);
 
/* -------------------------------- */
/* -------------------------------- */
/* -------------------------------- */
 
// Write the format to the card. We use object from the previous snippet code.
acService->writeFormat(format, location, aiToUse, aiToWrite);

Read access control format

// Read the format from the card. We use object from the previous snippet code.
boost::shared_ptr<logicalaccess::Format> retformat = acService->readFormat(format, location, aiToUse);
 
// Some chip access control service implementation could change the returned format.
// It is recommended to not use the given format in argument, but the returned one with appropriate tests.
 
/* -------------------------------- */
/* Example with Wiegand 26 format   */
/* -------------------------------- */
 
boost::shared_ptr<logicalaccess::Wiegand26Format> w26retformat = boost::dynamic_pointer_cast<logicalaccess::Wiegand26Format>(retformat);
 
if (w26retformat)
{
    std::cout << "Successfully read Wiegand 26 format. Uid: " << w26retformat->getUid() << std::endl;
}
 
/* -------------------------------- */
/* -------------------------------- */
/* -------------------------------- */

Low level chip command

The chip’s commands can be casted to the associated implementation to access low level chip command. The same logic can be applied to other generic object (reader provider, reader unit, chip, profile, card provider, location, access info, format …).

/* -------------------------------- */
/* Example with DESFire chip        */
/* -------------------------------- */
 
boost::shared_ptr<logicalaccess::DESFireCommands> desfirecmd = boost::dynamic_pointer_cast<logicalaccess::DESFireCommands>(chip->getCommands());
 
// Select the AID 0x521
desfirecmd->selectApplication(0x521);
 
/* -------------------------------- */
/* -------------------------------- */
/* -------------------------------- */

Handle exception

try
{
  // DO CONTACTLESS STUFF HERE
  // DO CONTACTLESS STUFF HERE
  // DO CONTACTLESS STUFF HERE
}
catch(logicalaccess::LibLogicalAccessException& ex)
{
  std::cout << "LibLogicalAccess exception: " << ex.what() << std::endl;
}

Iterate the chip memory areas

// Get the root node
boost::shared_ptr<logicalaccess::LocationNode> rootNode = chip->getRootLocationNode();
// Get childrens of this node
std::vector<boost::shared_ptr<logicalaccess::LocationNode> > childs = rootNode->getChildrens();
for (std::vector<boost::shared_ptr<logicalaccess::LocationNode> >::iterator i = childs.begin(); i != childs.end(); ++i)
{
  // Display node information
  std::cout << "Size of node " << (*i)->getName() << ": " << ((*i)->getLength() * (*i)->getUnit()) << " bytes";
 
  Get the associated location for that node (to read or write data for example)
  boost::shared_ptr<logicalaccess::Location> childlocation = (*i)->getLocation();
}

Create your own Library for LibLogicalAccess

Each Reader and Card is a Library with LibLogicalAccess. If you want to add your own Reader or Card, you just have to build a Library with Library name and entry well named.

Library Name:

  • <Name>Readers.[dll/so] : This Library creates Readers.
  • <Name>Cards.[dll/so]: This Library creates Cards.
  • <Name>Unified.[dll/so]: This Library can create Readers and Cards.

For example, if you want a library named Foo who create Cards in windows: FooCards.dll

Library Entry Name:

  • get<Name>Reader: This Library entry will create the Reader.
  • get<Name>Chip: This Library entry will create the Chip.

Example with the Library Foo with the Reader Foo2K

extern "C"
{
	LIBLOGICALACCESS_API char *getLibraryName()
	{
		return (char *)"Foo";
	}
 
	LIBLOGICALACCESS_API void getFoo2KReader(boost::shared_ptr<logicalaccess::Foo2KReaderProvider>* rp)
	{
		 if (rp != NULL)
		 {
		 	 *rp = logicalaccess::Foo2KReaderProvider::getSingletonInstance();
		 }
	}
 
	LIBLOGICALACCESS_API bool getReaderInfoAt(unsigned int index, char* readername, size_t readernamelen, void** getterfct)
	{
		bool ret = false;
		if (readername != NULL && readernamelen == PLUGINOBJECT_MAXLEN && getterfct != NULL)
		{
			switch (index)
			{
			case 0:
				{
					*getterfct = (void*)&getFoo2KReader;
					sprintf(readername, READER_FOO2K);
					ret = true;
				}
				break;
			}
		}
 
		return ret;
	}
}

Sample code that use LibLogicalAccess and who wants the Foo2K Reader Provider.

boost::shared_ptr<logicalaccess::ReaderProvider> foo2kprovider = logicalaccess::LibraryManager::getInstance()->getReaderProvider("Foo2K");
//...

Read Generic/Custom Card Fields

#include "logicalaccess/dynlibrary/idynlibrary.hpp"
#include "logicalaccess/dynlibrary/librarymanager.hpp"
#include "logicalaccess/readerproviders/readerconfiguration.hpp"
#include "logicalaccess/services/storage/storagecardservice.hpp"
#include "logicalaccess/services/accesscontrol/readerformatcomposite.hpp"
#include "logicalaccess/services/accesscontrol/formats/customformat/numberdatafield.hpp"
#include "logicalaccess/services/accesscontrol/formats/customformat/asciidatafield.hpp"
#include "logicalaccess/services/accesscontrol/formats/customformat/binarydatafield.hpp"
 
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <stdlib.h>
 
 
std::string ToLower(std::string data)
{
	std::string ret;
	ret.resize(data.size());
	std::transform(data.begin(), data.end(), ret.begin(), ::tolower);
	return ret;
}
 
 
/**
 * \brief The application entry point.
 * \param argc The arguments count.
 * \param argv The arguments.
 */
int main(int , char**)
{
	try
	{
 
		std::ifstream config;
		std::string configxml;
 
		config.open("config.xml");
		if (!config.is_open())
			return -1;
		while (!config.eof())
		{
			std::string tmp;
			getline(config, tmp);
			configxml += tmp;
		}
		config.close();
		std::cout << configxml << std::endl;
 
		boost::shared_ptr<logicalaccess::ReaderFormatComposite> readerformatconfig(new logicalaccess::ReaderFormatComposite());
		boost::dynamic_pointer_cast<logicalaccess::XmlSerializable>(readerformatconfig)->unSerialize(configxml, "");
 
		boost::shared_ptr<logicalaccess::ReaderConfiguration> readerConfig(readerformatconfig->getReaderConfiguration());
		boost::shared_ptr<logicalaccess::ReaderProvider> readerProvider(readerConfig->getReaderProvider());
		boost::shared_ptr<logicalaccess::ReaderUnit> readerUnit(readerConfig->getReaderUnit());
		boost::shared_ptr<logicalaccess::CardsFormatComposite> cardsFormatComposite;
 
		if (!readerUnit)
		{
			readerUnit = readerProvider->createReaderUnit();
		}
		cardsFormatComposite = readerformatconfig->getCardsFormatComposite();
 
		while (1)
		{
			readerUnit->connectToReader();
			std::cout << "Time start : " << time(NULL) << std::endl;
			if (readerUnit->waitInsertion(15000))
			{
				if (readerUnit->connect())
				{
					std::cout << "Card inserted on reader \"" << readerConfig->getReaderUnit()->getConnectedName() << "\"." << std::endl;
					boost::shared_ptr<logicalaccess::Chip> chip = readerConfig->getReaderUnit()->getSingleChip();
					if (chip)
					{
						std::cout << "Card type: " << chip->getCardType() << std::endl;
						if (cardsFormatComposite)
						{
							boost::shared_ptr<logicalaccess::Format> format;
							boost::shared_ptr<logicalaccess::Location> location;
							boost::shared_ptr<logicalaccess::AccessInfo> accessinfo, aiwrite;
 
							logicalaccess::CardTypeList cardlist = cardsFormatComposite->getConfiguredCardTypes();
							for (logicalaccess::CardTypeList::iterator it = cardlist.begin(); it < cardlist.end(); ++it)
							{
								if (chip->getCardType() ==	*it || chip->getGenericCardType() == *it || ToLower(*it).find("generic") == 0)
								{
									std::vector<unsigned char> number = readerUnit->getNumber(chip);
									std::cout << "CSM: " << logicalaccess::BufferHelper::getHex(number) << std::endl;
									boost::shared_ptr<std::map<std::string, std::string> > valuesToSend(new std::map<std::string, std::string>);
 
									cardsFormatComposite->retrieveFormatForCard(*it, &format, &location, &accessinfo, &aiwrite);
 
									if (format)
									{
										cardsFormatComposite->setReaderUnit(readerUnit);
										boost::shared_ptr<logicalaccess::Format> readFormat = cardsFormatComposite->readFormat();
 
										if (readFormat)
										{
											std::list<boost::shared_ptr<logicalaccess::DataField> > fields = readFormat->getFieldList();
 
											for (std::list<boost::shared_ptr<logicalaccess::DataField> >::iterator itdata = fields.begin(); itdata != fields.end(); ++itdata)
											{
												if (boost::dynamic_pointer_cast<logicalaccess::NumberDataField>(*itdata))
												{
													boost::shared_ptr<logicalaccess::NumberDataField> ndf = boost::dynamic_pointer_cast<logicalaccess::NumberDataField>(*itdata);
 
													std::string tmp;
													std::stringstream strstream;
													strstream << ndf->getValue();
													strstream >> tmp;
													std::cout << "NumberDataField: " << tmp << std::endl;
													valuesToSend->insert(std::pair<std::string, std::string>(ToLower(ndf->getName()), tmp));
												}
												else if (boost::dynamic_pointer_cast<logicalaccess::BinaryDataField>(*itdata))
												{
													boost::shared_ptr<logicalaccess::BinaryDataField> bdf = boost::dynamic_pointer_cast<logicalaccess::BinaryDataField>(*itdata);
													std::vector<unsigned char> array = bdf->getValue();
													if (array.size() > 0)
													{
														std::string str(array.begin(), array.end());
														std::cout  << "BinaryDataField: " << str << std::endl;
														valuesToSend->insert(std::pair<std::string, std::string>(bdf->getName(), str));
													}
												}
												else if (boost::dynamic_pointer_cast<logicalaccess::ASCIIDataField>(*itdata))
												{
													boost::shared_ptr<logicalaccess::ASCIIDataField> adf = boost::dynamic_pointer_cast<logicalaccess::ASCIIDataField>(*itdata);
													valuesToSend->insert(std::pair<std::string, std::string>(adf->getName(), adf->getValue()));
													std::cout << "ASCIIDataField: " << adf->getValue() << std::endl;
												}
											}
										}
									}
								}
							}
						}
 
					}
 
					readerUnit->disconnect();
				}
				else
				{
					std::cout << "Error: cannot connect to the card." << std::endl;
				}
 
				std::cout << "Logical automatic card removal in 15 seconds..." << std::endl;
 
				if (!readerConfig->getReaderUnit()->waitRemoval(15000))
				{
					std::cerr << "Card removal forced." << std::endl;
				}
 
				std::cout << "Card removed." << std::endl;
			} else
			{
				std::cout << "No card inserted." << std::endl;
			}
		}
	}
	catch (std::exception& ex)
	{
		std::cout << ex.what() << std::endl;
	}
 
	return EXIT_SUCCESS;
}
api-how-to-examples.txt · Last modified: 2014/01/21 11:01 by adrien