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
- r_card()
- initialize()
- set_option()
- help_options()
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.