Evolis Zenius is a color or monochrome card printer. Evolis offers SpringCard CrazyWriter PC/SC (ISO 14443, ISO 15693 + 2 SAM) as the contactless encoding option for Zenius -as well as for the other printers in its portfolio. Zenius plus CrazyWriter makes it easy to issue personalized cards on-the-field.
In this article we'll show how to synchronize the card encoding part (CrazyWriter PC/SC) with the card printing job using Evolis' SDK. Our sample project (C# source code available in the PC/SC SDK, under folder
/samples/dotnet/ZeniusVCard) is a real-world example: we print a business card on a Desfire EV1 smartcard, and we store a vCard object into the Desfire, following NFC Forum standard known as 'NFC Forum Type 4 tag'. Doing so, the business card goes NFC and could be read by any compliant smartphone, that will automatically add the vCard data to its contact list! All you need to try the demo by yourself is a blank and virgin Desfire EV1 card, and, of course, an Evolis Zenius printer featuring SpringCard CrazyWriter.
In a nutshell
To print and encode a vCard, the process is as follows:
- Ask the printer to take one card in the feeder, and to put it in position for encoding (in front of the CrazyWriter's antenna),
- Recognize the card, format it if needed, write the data,
- Launch the print job,
- Optionnaly repeat the process, until there is no card left in the feeder.
The process always encodes a card before printing it. Doing so, should any problem append (not the expected type of card, card locked read-only...), the card is ejected immediately. No time nor ribbon has been waisted printing a useless card.
There are two ways to communicate with an Evolis printer:
- using the Windows spooler (as with any other printer),
iomem.dll, a communication library supplied within Evolis' SDK.
Sending print jobs to the spooler is straightforward as all the steps of the printing are handled automatically by the system. Unfortunately, once the job is launched, the software has no way to know where the card actually is in the printer nor to stop it for a few seconds in front of the antenna..
On the other end, sending low level commands through
iomem.dll offers a lot of flexibility, but lots of things have to be re-implemented in the printing software. This requires a specific expertise and can be time consuming.
So we'll take the best of the two worlds:
iomem.dll will be used to drive the card in the printer until the CrazyWriter has done its job, and afterwards a print job will be sent to the spooler to actually print the card. We'll also have to use
iomem.dll again to detect the end of the print job, so our software will not try to insert another card in the path until the previous card has been printed and ejected.
Step by step explanation of the sample project
Selecting the target printer and contactless coupler
The .NET PrintDialog object (
System.Windows.Controls.PrintDialog) if the easiest way to select a printer. The name of the selected printer is returned in
There's no immediate way to know which CrazyWriter (or in general which PC/SC reader) belongs to the selected printer. So we display our common 'Select PC/SC Reader' dialog to let the user find the reader. Default is to select the contactless interface of the first available CrazyWriter.
Controlling the printer through iomem.dll
First step is to gain access to
iomem.dll's entry points from our C# application. The function used are:
Please refer to Evolis' SDK for a detailed documentation of the DLL.
OpenPebble(PrinterName) gives use access to the printer, we then can use the couple
ReadPebble to send arbitrary commands to the printer -and wait for its answer.
Here are the 3 only commands we need:
Rlr;h to check whether the feeder is empty,
Sic to load a card from the feeder, and to move it into position for encoding (in front of the CrazyWriter's antenna),
Se to eject the card (in case the encoding has failed).
If the encoding is successful, sending a print job to the spooler is enough to make the printer take the card from its current position (in front of the antenna), print it, and eject it.
To know whether the print job is terminated or still pending, we'll use a very simple trick: as the printer is not available to answer to
iomem.dll commands while it is under control of the system's spooler, we'll send repeated dummy commands, and we'll know that the job is ended when we'll get an answer at last. The dummy command is:
Rfv read firmware version
Please also refer to Evolis' SDK for details regarding the printer's command set.
Encoding the vCard on the contactless card
This part is shared with the vCard part of NFCTool, another of our samples. The only difference is that NFCTool can also read cards, and implements a 'wake up on card arrival' scheme that doesn't have to be implemented in this sample. The card 'arrives' only after a successful invocation of the "
Sic" control command.
We start by opening a PC/SC channel to the card:
scard = new SCardChannel(ReaderName) (see the documentation of our PC/SC for .NET API for details).
Then we use the methods of our NfcTag object (
NfcTag.BackgroundRecognize) to check whether the card is a NFC Forum tag or not. It must be either already formatted (and offering enough memory space to store the vCard) or a Desfire EV1 that we know how to format and write. Note that
BackgroundRecognize, as the name says, performs the recognition in a background thread and invoke a callback function once done. This is generally speaking a good practice to implement card-related stuff in a background thread so the application's window remains 'alive' even if the card takes its time to answer. At this step, the card is now for sure compliant with NFC Forum type 4 specification (or has been ejected if not, or if the user has chosen not to overwrite existing data).
Eventually, a new
NfcVCard object is created, populated with the data entered by the user, and inserted as the content of the
NfcTag objet. The the
NfcTag.BackgroundWrite method is called, so the vCard content goes actually into the card. Once again this is done in a background thread.
Printing the layout on the card
At the end of the writing (that takes no more than one second anyway), the callback that is invoked launches the print job.
To print our business card, we process as follow:
- Create a PrintDocument object (
- Add to this PrintDocument object a PrintPageEventHandler function that will be invoked to actually draw the layout,
- Code the PrintPageEventHandler to implement the drawing of the business card from the data entered by the user,
- Invoke the
PrintDocument.Print() method to send it to the spooler.
In this example, the PrintPageEventHandler is implemented in the FormatBusinnessCard function. The name and the title are printed in the middle of the card, respectively in Arial 16 and Arial 14; the contact information (business phone and e-mail) are in the down-left corner in Arial 10; the picture is printed in the up-right corner; etc... Of course this is the first thing you'll have to change to design your cards according your own layout.
Waiting for the end of the job
PrintDocument.Print() has been called, there's nothing else to do but wait. The spooler works in background, so the application is free to do anything else, but we can't start encoding another card until the current one has been printed and ejected. Therefore we implement a waiting loop, sending the "
Rfv" command through
iomem.dll repeatedly. Once the printer responds, we know that the job is over. We could then loop to go on with the next card.