SCAM Documentation

Tim TimeWaster <tim@cuba.xs4all.nl>

1. Adding a New Reader

This part of the manual assumes you know how to program in C++. It may not be complete. May the source be with you!

A new reader for SCAM can consist of code that communicates with a physical smart card reader (like the "dumbmouse" reader), or code that implements a protocol or certain functions (like the "t1" reader).

1.1 Writing the Driver Code

The rascal subdirectory contains all the driver code for the readers, protocols and applications.

1.1.1 Physical Readers

The t_reader class is an abstract class that specifies all the functions a reader should implement. These include:

Constructors/Destructors

t_reader()
Constructs the object, without initializing anything, or initializing some default parameters (e.g. a default device). This constructor is never called from SCAM.
t_reader(const char *d)
This constructs the object and lets it use d as its device.
~t_reader()
This will destroy the object.

Communication Settings

All these functions apply to the communication between the reader and the smart card, not the communication between the reader and the computer! Most of them do not need to be implemented for "smart" readers, or cannot even be implemented for some readers.
int speed()
returns the baudrate that is used to communicate with the card. This value is used (internally) in other classes to determine the value of the etu. It is not the baudrate that (for example) the serial port uses to communicate with the reader!
void set_speed(int s)
sets the baudrate that is used to communicate with the card to s. It is not the baudrate that (for example) the serial port uses to communicate with the reader!
int wait_etu()
returns the default time that we should wait for card output in etu.
long wait_us()
returns the default time that we should wait for card output in microseconds.
void set_wait_etu(int etu)
sets the default waiting time to etu etu.
void set_wait_us(long us)
sets the default waiting time to us microseconds.
t_parity parity()
returns the parity that is used. The t_parity type is defined in the file parity.h.
void set_parity(t_parity parity)
sets the parity to parity. The parity usually depends on the convention that is used.

Communication

These functions apply to the communication to the card, not to the reader. The driver implementation should handle the embedding into a reader protocol and things like that.
void ISO7816_reset()
resets the smart card. The first thing that should be read after the reset is the ATR.
int ISO7816_write(const unsigned char *buf, int len)
sends len bytes from the buffer buf to the card. Returns the number of bytes that were succesfully written.
int ISO7816_read()
reads a byte from the card. This function will use the default waiting time specified by wait_us. Returns -1 if no input is available.
int ISO7816_read(long wait)
reads a byte from the card. This function will use a waiting time of wait microseconds. Returns -1 if no input is available.
void flush()
Discards all data that the card has sent but has not been read yet.

Miscellaneous

These functions are extras. Not every reader implements them, but a lot of readers do.
bool probe_reader()
returns true if the correct reader is connected.
bool probe_card()
returns true if a card is present.
bool auto_convention()
specifies wether the reader translates input and output, as specified by the convention, itself or not. Returns true if it does.

To implement your favourite reader, derive a class from the t_reader class (or a class derived from it) in which you implement all the abstract functions of its base class.

For examples, see the readers that are already implemented. For readers that use the serial port, a t_serial_reader class was designed, that uses the t_serial datatype that is implemented in serial.h. It is implemented in ser_reader.h. It is adviced to derive such a reader's implementation from this class, as it will then have to use the (portable) t_serial class.

1.1.2 Other Readers

The rascal directory contains more than just physical reader code. Implementations for ISO 7816-3 protocols can also be found. Details can be found in the RASCaL manual.

You may want to use these implementations for your code.

1.2 Making a SCAM Interface for the Reader

Now that you have written the reader code, you should make an interface for SCAM. SCAM, to be precise the its interpreter in scam_interpreter.h, sees a reader as a variable of type t_scr *, which is defined in scr.h.

The t_scr class is an abstract class. Its derived classes should interpret reader specific commands and initialization options. To make life easier a few standard routines, such as for passing reader options or parsing reader specific commands have already been implemented in this abstract class.

To implement a reader, derive a class from t_scr (or a class derived from it) and implement all the necessary functions. For the parsing you will have to know how the lexical scanner class t_scam_scanner in sscanner.h works.

For a non-physical reader, you may want to derive your class from t_scr_soft, thereby giving it access to all physical readers that are implemented.

1.2.1 The Scamreader (t_scr) class

The t_scr class is derived from the t_interpreter class, which means that you do not have to write your own interpreter functions. This means you can use the lexical scanner p_s, the output stream *p_out and the error stream *p_err. See interpreter.h for details.

The t_scr class provides the following functions and variables:

Constructors/Destructors

t_scr(t_scam_scanner &s, ostream *out, ostream *err)
Constructs the object. It uses s to read its input, out to write its output to, and err to write its errors to.

Reader Commands

virtual int exec()
reads from the scanner p_s and executes the corresponding command. The four commands below are common to all readers. A general implementation for these commands already exist. You can add other commands here. It returns 0 if no command could be executed.
virtual void reset()
Reads arguments to the reset command and resets the card. You do not have to implement this function, but the function r_reset, which is called here.
virtual void write()
Reads arguments to the send command and writes it to the card. You do not have to implement this function, but the function r_write, which is called here.
virtual void read()
Reads arguments to the dump command and reads from the card. You do not have to implement this function, but the function r_read, which is called here.
virtual void flush()
Reads arguments to the flush command and flushes the card's output. You do not have to implement this function, but the function r_flush, which is called here.

Reader Options

virtual int init()
Parses the reader options and returns 0 if some error occured during the parsing. The t_scr class provides a standard way of handling options, in which the set_option is called. Invalid option names are ignored. You do not have to implement this function if you want to use the standard way.
virtual void set_option(const char *name, const char *val)
Checks wether the option name exists and gives it the value val. You have to implement this function (if you do not use it, just put the empty statement here).

Miscellaneous

// code necessary for initialization
virtual void initialize()
Really initializes the reader, i.e. a device is opened etc. This has to be done here, otherwise strange results will happen. You have to implement this function.
static int dump_mode
This variable is used to determine the output format for the dump function. Do not touch this.
protected:
char p_optname[scr_max_opt_name_length+1]
char p_optval[scr_max_opt_val_length+1]
Protected variables, which are used by the init function. It is wise not to touch these.
virtual void r_reset()
virtual void r_write(const unsigned char *, int)
virtual void r_flush()
virtual int r_read()
virtual bool r_card()
The functions that do the real work on the reader. You always have to implement these. The r_card function returns false if no card was detected, and true otherwise. Readers that do not implement a card detect function should return true here (if you are not using the t_scr_soft class).
virtual void dump()
Outputs all data that the smart card has output, but has not yet been read. The output is done according to the dump_mode variable.

So only a few functions have to be implemented. In addition you have to implement the settings function, which displays the current settings on *p_err, and help which shows help on the reader options on *p_err.

For examples, see the already implemented readers.

1.2.2 The Non-physical Scamreader class (t_scr_soft)

The t_scr_soft class implements You have to implement settings() and help().

1.3 Adding the Reader to SCAM

Now all that is left is making the reader visible for SCAM. There is only one part of the code that will be affected: the file readernames.h.

Just add the right #include-lines to the file and add a line like this:

READER(name,scamreadertype,rascaltype)
where name is the name (in quotes), scamreadertype is a classname derived from t_scr (or a class derived from it), rascaltype is a classname derived from t_reader (or a class derived from it). rascaltype is not used for non-physical readers, so any value can be entered there for those readers.

If your new reader consists of not only header files, but also source files, make sure the object file is added to the list in the Makefile.

After compilation, SCAM will be able to use the new reader. Physical readers can even be used by non-physical readers by the reader= option.