EEPROMTest.java
//---------------------------------------------------------------------------------------
// EEPROM Test
// Demonstration for a test of the measurement of the maximum EEPROM write/erase
// cycles of a smart card microcontroller
// file: EEPROMTest.java
// uses: ICC.java
//
// This program uses the PassThruCardService from OCF opencard.opt.util package.
// Additional informations and reference implementation: www.opencard.org.
// Testet with Omnikey CardMan 4000 on PCMCIA port and the appropriate PC/SC drivers
// from Omnikey on Windows 2000. Testet with JBuilder 6 and JDK 1.3.1 and a
// special smart card in non personalized state.
//
// Uses OCFPCSC1.DLL, OCFPCSC1.DLL, pcsc-wrapper-2.0.jar, base-core.jar, base-opt.jar
// from OCF 1.2
// The content of the file "opencard.properties" must be changed to:
// OpenCard.terminals = com.ibm.opencard.terminal.pcsc10.Pcsc10CardTerminalFactory
// For understanding the mechanisms of OCF it is useful to look first into the
// SimpleOCF example.
//
// WARNING:  The usage of this programm is at your own risk. The execution of this
//           program will damage your smart card because of analysing the maximum
//           EEPROM write/erase-cycles using proprietary commands.
//
// Remark:   For this test a special smart card with proprietary commands for writing
//           and verifying data in EEPROM is neccessary.
//
// Run time estimation:      10 s run time             ->        201 erase-write-cycles
//                           60 s run time             ->      1 171 erase-write-cycles
//                          100 s run time             ->      1 919 erase-write-cycles
//                          600 s (= 10 min) run time  ->      9 871 erase-write-cycles
//                        3 600 s (=  1 h) run time    ->     71 732 erase-write-cycles
//                       10 800 s (=  3 h) run time    ->    215 165 erase-write-cycles
//                       36 000 s (= 10 h) run time    ->    716 779 erase-write-cycles
//                      180 000 s (= 50 h) run time    ->  3 600 000 erase-write-cycles
//
// Results with typical microcontrollers:
//      guaranted minimum write/erase cycles                   100 000
//      measured write/erase cycles in office environment  > 1 300 000 
//
// This source code is under GNU general public license (see www.opensource.org for details).
// Please send corrections and ideas for extensions to Wolfgang Rankl (www.wrankl.de)
// Copyright 2004 by Wolfgang Rankl, Munich
//
//  25. July 2004 - V 2, rw: improved documentation, fix bug concerning intermediate
//                           information, add run time estimation table, add results
//                           with typical microcontrollers, 1st published version
//  14. July 2004 - V 1, rw: initial runnable version
//---------------------------------------------------------------------------------------

package eeppack;

import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import javax.swing.*;

public class EEPROMTest extends JFrame implements ActionListener {
  static final boolean DEBUG = false;    // true: show APDUs; false: show application level information
  static final int FIRST_BYTE_ATR = 0;   // first byte of the ATR
  public static JTextArea ta = new JTextArea(20, 100);

  // definition of the EERPOM test scenario
  static final byte PATTERN1 =  (byte) 0x55;
  static final byte PATTERN2 =  (byte) 0xAA;
  static final byte STARTPAGE = (byte) 0x20;
  static final byte ENDPAGE =   (byte) 0x20;
  static final long INTINFO =             5;    // number of tests for intermediate information
  static final long TIMEOUT =            10;    // timeout of the test in s

  /** build the GUI with all the components
  */
  EEPROMTest() {
    //----- create text area with scroll pane
    ta.setTabSize(4);
    ta.setFont(new Font("Monospaced", 0, 12));     // Courier, 12 point size
    ta.setBackground(new Color(  0,   0,   0));    // black blue
    ta.setForeground(new Color(200, 255, 100));    // yellowgreen
    getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
    //----- create panel with buttons
    JPanel buttonPanel = new JPanel(new GridLayout(25, 1));
    JButton button1 = new JButton("Start Test");
    button1.addActionListener(this);
    buttonPanel.add(button1);
    JButton button2 = new JButton("Exit");
    button2.addActionListener(this);
    buttonPanel.add(button2);
    getContentPane().add(buttonPanel, BorderLayout.EAST);
  } // EEPROMTest

  /** dispatcher which the main parts of the programm
   *  @param event event for the pressed button
   */
  public void actionPerformed(ActionEvent event) {
    boolean loopbreak;
    byte[] atr;
    int result;
    long starttime, deltatime, noofwrites;

    showText("\n-------------------------------------------\n");
    String cmd = event.getActionCommand();
    ICC icc = new ICC();

    if (cmd.equals("Start Test")) {
      try {
        showText("activate smart card\n\n");
        atr = icc.start();
        if (atr[FIRST_BYTE_ATR] != 0) {
          // no error occur, a smart card is in the terminal, ATR received
          showText ("ATR [hex]:  " + formatATR(atr) + "\n");

          showText("start time: " + getFormatedDateTime() + "\n");
          loopbreak = false;
          starttime = getLongTime();
          noofwrites = 0;
          //----- this is the main loop of the program
          do {
            deltatime = (getLongTime() - starttime)/1000;    // deltatime is in seconds
            noofwrites++;
            if ((noofwrites % 2) == 0) {
              result = icc.write(PATTERN1, STARTPAGE, ENDPAGE);
            } // if
            else {
              result = icc.write(PATTERN2, STARTPAGE, ENDPAGE);
            } // else
            if (result != ICC.NO_ERROR) loopbreak = true; // write error occured
            if (deltatime >= TIMEOUT) loopbreak = true;   // timeout reached
            if ((noofwrites % INTINFO) == 0) {
              showText("\nnumber of write-erase-cycles: " + noofwrites + "\n");
              showText("time from start             : " + deltatime + " s\n");
              System.out.println(noofwrites);    // message that programm is still alive
            } // if
          } while (loopbreak == false);
          showText("\n");
          if (deltatime >= TIMEOUT) {
            showText("reason for break:                timeout of " + TIMEOUT + " s reached\n");
          } // if
          else {
            if (result == ICC.ERROR_AFTER_WRITE) {
              showText("reason for break:                EEPROM error after write\n");
            } // if
            if (result == ICC.ERROR_AFTER_COMPARE) {
              showText("reason for break:                EEPROM error after compare\n");
            } // if
          } // else
          showText("stop time:                       " + getFormatedDateTime() + "\n");
          showText("test duration:                   " + deltatime + " s\n");
          showText("no of EEPROM write-erase-cycles: " + noofwrites + "\n");
          showText("\ndeactivate smart card\n");
          icc.stop();
        } // if
        else {
          showText ("no smart card in the terminal\n");
        } // else
      } // try
      catch (Exception e) {
        System.err.println("caught exception '" + e.getClass() + "' - " + e.getMessage() );
      } // catch
    } // if

    else if (cmd.equals("Exit")) {
      showText("exit button pressed\n");
      showText("stop program GUI\n");
      System.exit(0);
    } // else if
    showText("-------------------------------------------\n");
  } // actionPerformed


  /** show text in the text window
   *  @param text text string to show on the display
   */
  public static void showText(String text) {
    ta.setText(ta.getText() + text);
  } // showText


  /** creates a long value for the time
   *  @return: number of milliseconds since January 1, 1970,
   */
  public static long getLongTime() {
    long l;
    Date time = new Date();
    l = time.getTime();
    return l;
  } // getLongTime


  /** creates a Windows conform formated date and time string
   *  @return: data and time string
   */
  public static String getFormatedDateTime() {
    String s;
    Date t = new Date();
    t.getTime();
    s = DateFormat.getDateTimeInstance().format(t);
    return s;
  } // getFormatedDateTime

  /** format a ATR
   *  @param atr ATR byte string with the raw ATR data in hex
   *  @return ATR string with the ATR in hex
   */
  public String formatATR(byte[] atr) {
    int n, x;
    String w = new String();
    String s = new String();

    w = "ATR: ";
    for (n = 0; n < atr.length; n++) {
      x = (int) (0x000000FF & atr[n]);
      w = Integer.toHexString(x).toUpperCase();
      if (w.length()== 1) w = "0" + w;
      s = s + w + " ";
    }  // for
    return s;
  } // showATR


  /** format a command APDU
   *  @param CmdAPDU  byte string with the raw command APDU
   *  @param LenCmdAPDU length of the raw command APDU bytw string
   *  @return  formated string with the command APDU
   */
  public static String formatCmdAPDU(byte[] CmdAPDU, int LenCmdAPDU) {
    int n, x;
    String w = new String();
    String s = new String();

    s = "IFD->ICC: ";
    for (n = 0; n < LenCmdAPDU; n++) {
      x = (int) (0x000000FF & CmdAPDU[n]);
      w = Integer.toHexString(x).toUpperCase();
      if (w.length() == 1) w = "0" + w;
      s = s + w + " ";
    }  // for
    return s;
   } // formatCmdAPDU


  /** format a response APDU
   *  @param RspAPDU byte string with the raw response APDU
   *  @param LenRspAPDU length of the raw response APDU bytw string
   *  @return formated string with the response APDU
   */
  public static String formatRspAPDU(byte[] RspAPDU, int LenRspAPDU) {
    int n, x;
    String w = new String();
    String s = new String();

    s = "ICC->IFD: ";
    for (n = 0; n < LenRspAPDU; n++) {
      x = (int) (0x000000FF & RspAPDU[n]);
      w = Integer.toHexString(x).toUpperCase();
      if (w.length()== 1) w = "0" + w;
      s = s + w + " ";
    }  // for
    return s;
  } // formatRspAPDU


 /** main
  *  @param args there will be no arguments for the main
  */
  public static void main(String [] args){
    int i;
    String s = new String();

    //--- build the GUI and set the parameters
    EEPROMTest et = new EEPROMTest();
    et.setLocation(0, 0);
    et.pack();
    et.setTitle("EEPROM Test");
    et.setVisible(true);

    //--- print the parameters for the EEPROM test
    et.showText("start EEPROM Test\n\n");
    et.showText("test parameters\n");
    i = (int) (0x000000FF & PATTERN1);
    s = Integer.toHexString(i).toUpperCase();
    et.showText("  1st test pattern                     0x" + s + "\n");
    i = (int) (0x000000FF & PATTERN2);
    s = Integer.toHexString(i).toUpperCase();
    et.showText("  2nd test pattern                     0x" + s + "\n");
    et.showText("  first tested EEPROM page             " + STARTPAGE + "\n");
    et.showText("  last tested EEPROM page              " + ENDPAGE + "\n");
    i = ENDPAGE - STARTPAGE + 1;
    et.showText("  number of tested EEPROM pages        " + i + "\n");
    et.showText("  timeout of the test                  " + TIMEOUT + " s\n");
    et.showText("  intermediate information every       " + INTINFO + " test\n");
    if (DEBUG == true) et.showText("  debug information                    yes\n");
    else et.showText("  debug information                    no\n");

    et.showText("\n\npress \"Start Test\" for beginning the test\n");
  } // main
} // class
//---------------------------------------------------------------------------------------




EEPROMTest.java