SHADebitDemo

SHADebitDemo.java
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.application.sha.*;
import com.dalsemi.onewire.container.*;
import com.dalsemi.onewire.utils.*;
import com.dalsemi.onewire.*;
import java.util.*;
import java.io.*;

public class SHADebitDemo
{

   /** turns on DEBUG messages */
   static final boolean DEBUG = false;

   public static void main(String[] args)
   {
      //coprocessor
      long coprID = 0;

      // ------------------------------------------------------------
      // プロパティファイルthe sha.properties を開きプロパティを読み込む
      // ------------------------------------------------------------
        try
        {
           FileInputStream prop_file
              = new FileInputStream("sha.properties");
           sha_properties = new Properties();
           sha_properties.load(prop_file);
        }
        catch(Exception e)
        {
           sha_properties = null;
        }



      // ------------------------------------------------------------
      // コプロセッサのコンテナを初期化する
      // ------------------------------------------------------------
      SHAiButtonCopr copr = null;
      OneWireContainer18 copr18 = new OneWireContainer18();
      copr18.setSpeed(DSPortAdapter.SPEED_OVERDRIVE, false);
      copr18.setSpeedCheck(false);

      // ------------------------------------------------------------
      // コプロセッサのアダプターを設定する
      // ------------------------------------------------------------
      DSPortAdapter coprAdapter = null;
      String coprAdapterName = null, coprPort = null;
      try
      {
         coprAdapterName = getProperty("copr.adapter");
         coprPort = getProperty("copr.port");

         if(coprPort==null || coprAdapterName==null)
         {
            coprAdapter = OneWireAccessProvider.getDefaultAdapter();
         }
         else
         {
            coprAdapter
               = OneWireAccessProvider.getAdapter(coprAdapterName, coprPort);
         }

         IOHelper.writeLine("Coprocessor adapter loaded, adapter: " +
                            coprAdapter.getAdapterName() +
                            " port: " + coprAdapter.getPortName());

         coprAdapter.adapterDetected();
         coprAdapter.targetFamily(0x18);
         coprAdapter.beginExclusive(true);
         coprAdapter.reset();
         coprAdapter.setSearchAllDevices();
         coprAdapter.reset();
         coprAdapter.putByte(0x3c);
         coprAdapter.setSpeed(coprAdapter.SPEED_OVERDRIVE);
      }
      catch(Exception e)
      {
         IOHelper.writeLine("Error initializing coprocessor adapter");
         e.printStackTrace();
         System.exit(1);
      }

      // ------------------------------------------------------------
      // コプロセッサを探す
      // ------------------------------------------------------------
      if(getPropertyBoolean("copr.simulated.isSimulated", false))
      {
         String coprVMfilename = getProperty("copr.simulated.filename");
         // ---------------------------------------------------------
         // エミュレートされたコプロセッサをロードする
         // ---------------------------------------------------------
         try
         {
            copr = new SHAiButtonCoprVM(coprVMfilename);
         }
         catch(Exception e)
         {
            IOHelper.writeLine("Invalid Coprocessor Data File");
            e.printStackTrace();
            System.exit(1);
         }
      }
      else
      {
         // ---------------------------------------------------------
         // コプロセッサのサービスファイルの名前を得る
         // ---------------------------------------------------------
         String filename = getProperty("copr.filename","COPR.0");

         // ---------------------------------------------------------
         // ハードウェアのコプロセッサのアドレスをチェックする
         // ---------------------------------------------------------
         byte[] coprAddress = getPropertyBytes("copr.address",null);
         long lookupID = 0;
         if(coprAddress!=null)
         {
            lookupID = Address.toLong(coprAddress);

            IOHelper.write("Looking for coprocessor: ");
            IOHelper.writeLineHex(lookupID);
         }

         // ---------------------------------------------------------
         // ハードウェアのコプロセッサを探す
         // ---------------------------------------------------------
         try
         {
            boolean next = coprAdapter.findFirstDevice();
            while(copr==null && next)
            {
               try
               {
                  long tmpCoprID = coprAdapter.getAddressAsLong();
                  if(coprAddress==null || tmpCoprID==lookupID)
                  {
                     IOHelper.write("Loading coprocessor file: " + filename +
                                    " from device: ");
                     IOHelper.writeLineHex(tmpCoprID);

                     copr18.setupContainer(coprAdapter, tmpCoprID);
                     copr = new SHAiButtonCopr(copr18, filename);

                     //save coprocessor ID
                     coprID = tmpCoprID;
                  }
               }
               catch(Exception e)
               {
                  IOHelper.writeLine(e);
               }

               next = coprAdapter.findNextDevice();
            }
         }
         catch(Exception e)
         {;}

      }

      if(copr==null)
      {
         IOHelper.writeLine("No Coprocessor found!");
         System.exit(1);
      }

      IOHelper.writeLine(copr);
      IOHelper.writeLine();


      // ------------------------------------------------------------
      // SHADebitの取引タイプを作成する
      // ------------------------------------------------------------
      //stores DS1963S transaction type
      SHATransaction debit18 = null;

      String transType18 = getProperty("transaction.type", "signed");
      transType18 = transType18.toLowerCase();
      if(transType18.equals("signed"))
      {
         debit18 = new SHADebit(copr,10000,50);
      }
      else
      {
         debit18 = new SHADebitUnsigned(copr,10000,50);
      }

      //Transaction super class, swap variable
      SHATransaction trans = null;

      // ------------------------------------------------------------
      // ds1961Sに対する書き込み信用照会を得る 
      // ------------------------------------------------------------
      //first get the write authorization adapter
      DSPortAdapter authAdapter = null;
      String authAdapterName = null, authPort = null;
      try
      {
         authAdapterName = getProperty("ds1961s.copr.adapter");
         authPort = getProperty("ds1961s.copr.port");

         if(authAdapterName==null || authAdapterName==null)
         {
            if(coprAdapterName!=null && coprPort!=null)
               authAdapter = OneWireAccessProvider.getDefaultAdapter();
            else
               authAdapter = coprAdapter;
         }
         else if(coprAdapterName.equals(authAdapterName) &&
                 coprPort.equals(authPort))
         {
            authAdapter = coprAdapter;
         }
         else
         {
            authAdapter
               = OneWireAccessProvider.getAdapter(authAdapterName, authPort);
         }

         IOHelper.writeLine("Write-Authorization adapter loaded, adapter: " +
                            authAdapter.getAdapterName() +
                            " port: " + authAdapter.getPortName());

         byte[] families = new byte[]{0x18};

         authAdapter.adapterDetected();
         authAdapter.targetFamily(families);
         authAdapter.beginExclusive(false);
         authAdapter.reset();
         authAdapter.setSearchAllDevices();
         authAdapter.reset();
         authAdapter.putByte(0x3c);
         authAdapter.setSpeed(DSPortAdapter.SPEED_OVERDRIVE);
      }
      catch(Exception e)
      {
         IOHelper.writeLine("Error initializing write-authorization adapter.");
         e.printStackTrace();
         System.exit(1);
      }

      //now find the coprocessor
      SHAiButtonCopr authCopr = null;

      // -----------------------------------------------------------
      // ハードウェアの書き込み信用照会コプロセッサのアドレスをチェックする
      // -----------------------------------------------------------
      byte[] authCoprAddress = getPropertyBytes("ds1961s.copr.address",null);
      long lookupID = 0;
      if(authCoprAddress!=null)
      {
         lookupID = Address.toLong(authCoprAddress);

         IOHelper.write("Looking for coprocessor: ");
         IOHelper.writeLineHex(lookupID);
      }
      if(lookupID==coprID)
      {
         //it's the same as the standard coprocessor.
         //valid only if we're not signing the data
         authCopr = copr;
      }
      else
      {
         // ---------------------------------------------------------
         // 書き込み信用照会コプロセッサを探す
         // ---------------------------------------------------------
         try
         {
            String filename = getProperty("ds1961s.copr.filename","COPR.1");
            OneWireContainer18 auth18 = new OneWireContainer18();
            auth18.setSpeed(DSPortAdapter.SPEED_OVERDRIVE, false);
            auth18.setSpeedCheck(false);

            boolean next = authAdapter.findFirstDevice();
            while(authCopr==null && next)
            {
               try
               {
                  long tmpAuthID = authAdapter.getAddressAsLong();
                  if(authCoprAddress==null || tmpAuthID==lookupID)
                  {
                     IOHelper.write("Loading coprocessor file: " + filename +
                                    " from device: ");
                     IOHelper.writeLineHex(tmpAuthID);

                     auth18.setupContainer(authAdapter, tmpAuthID);
                     authCopr = new SHAiButtonCopr(auth18, filename);
                  }
               }
               catch(Exception e)
               {
                  IOHelper.writeLine(e);
               }

               next = authAdapter.findNextDevice();
            }
         }
         catch(Exception e)
         {
            IOHelper.writeLine(e);
         }
         if(authCopr==null)
         {
            IOHelper.writeLine("no write-authorization coprocessor found");
            if(copr instanceof SHAiButtonCoprVM)
            {
               authCopr = copr;
               IOHelper.writeLine("Re-using SHAiButtonCoprVM");
            }
         }
      }

      IOHelper.writeLine(authCopr);
      IOHelper.writeLine();

      // ------------------------------------------------------------
      // ユーザーのiButtonオブジェクトを作成する
      // ------------------------------------------------------------
      //holds DS1963S user buttons
      SHAiButtonUser18 user18 = new SHAiButtonUser18(copr);
      OneWireContainer18 owc18 = new OneWireContainer18();
      owc18.setSpeed(DSPortAdapter.SPEED_OVERDRIVE, false);
      owc18.setSpeedCheck(false);

      //holds DS1961S user buttons
      SHAiButtonUser33 user33 = new SHAiButtonUser33(copr, authCopr);
      OneWireContainer33 owc33 = new OneWireContainer33();
      owc33.setSpeed(DSPortAdapter.SPEED_OVERDRIVE, false);
      //owc33.setSpeedCheck(false);

      //Holds generic user type, swap variable
      SHAiButtonUser user = null;

      // ------------------------------------------------------------
      // ユーザーのためのアダプターを得る
      // ------------------------------------------------------------
      DSPortAdapter adapter = null;
      String userAdapterName = null, userPort = null;
      try
      {
         userAdapterName = getProperty("user.adapter");
         userPort = getProperty("user.port");

         if(userPort==null || userAdapterName==null)
         {
            if(coprAdapterName!=null && coprPort!=null)
            {
               if(authAdapterName!=null && authPort!=null)
                  adapter = OneWireAccessProvider.getDefaultAdapter();
               else
                  adapter = authAdapter;
            }
            else
               adapter = coprAdapter;
         }
         else if(userAdapterName.equals(authAdapterName) &&
            userPort.equals(authPort))
         {
            adapter = authAdapter;
         }
         else if(userAdapterName.equals(coprAdapterName) &&
            userPort.equals(coprPort))
         {
            adapter = coprAdapter;
         }
         else
         {
            adapter
               = OneWireAccessProvider.getAdapter(userAdapterName, userPort);
         }

         IOHelper.writeLine("User adapter loaded, adapter: " +
                            adapter.getAdapterName() +
                            " port: " + adapter.getPortName());

         byte[] families = new byte[]{0x18,0x33};
         families = getPropertyBytes("transaction.familyCodes", families);
         IOHelper.write("Supporting the following family codes: ");
         IOHelper.writeBytesHex(" ", families, 0, families.length);

         adapter.adapterDetected();
         adapter.targetFamily(families);
         adapter.beginExclusive(true);
         adapter.reset();
         adapter.setSearchAllDevices();
         adapter.reset();
         adapter.putByte(0x3c);
         adapter.setSpeed(DSPortAdapter.SPEED_OVERDRIVE);
      }
      catch(Exception e)
      {
         IOHelper.writeLine("Error initializing user adapter.");
         e.printStackTrace();
         System.exit(1);
      }

      //timing variables
      long t0=0, t1=0, t2=0, t3=0, t4=0, t5=0;

      //address of current device
      final byte[] address = new byte[8];

      //result of findNextDevice/findFirstDevice
      boolean next = false;

      //holds list of known buttons
      long[] buttons = new long[16];
      //count of how many buttons are in buttons array
      int index = 0;

      //temporary id representing current button
      long tmpID = -1;
      //array of buttons looked at during this search
      long[] temp = new long[16];
      //count of how many buttons in temp array
      int cIndex = 0;

      //flag indiciating whether or not temp array represents
      //the complete list of buttons on the network.
      boolean wholeList = false;

      System.out.println();
      System.out.println();
      System.out.println("**********************************************************");
      System.out.println("   Beginning The Main Application Loop (Search & Debit)");
      System.out.println("           Press Enter to Exit Application");
      System.out.println("**********************************************************");
      System.out.println();

      //application infinite loop
      for(boolean applicationFinished = false; !applicationFinished;)
      {
         try
         {
            if(coprAdapter!=adapter)
            {
               //in case coprocessor communication got hosed, make sure
               //the coprocessor adapter is in overdrive
               coprAdapter.setSpeed(adapter.SPEED_REGULAR);
               coprAdapter.reset();
               coprAdapter.putByte(0x3c); //overdrive skip rom
               coprAdapter.setSpeed(adapter.SPEED_OVERDRIVE);
            }
            if(authAdapter!=coprAdapter && authAdapter!=adapter)
            {
               //in case coprocessor communication with the write-
               //authorization coprocessor got hosed, make sure
               //the coprocessor adapter is in overdrive
               authAdapter.setSpeed(adapter.SPEED_REGULAR);
               authAdapter.reset();
               authAdapter.putByte(0x3c); //overdrive skip rom
               authAdapter.setSpeed(adapter.SPEED_OVERDRIVE);
            }
         }
         catch(Exception e){;}

         // ---------------------------------------------------------
         // 新しいiButtonを探す
         // ---------------------------------------------------------
         boolean buttonSearch = true;

         //Button search loop, waits forever until new button appears.
         while(buttonSearch && !applicationFinished)
         {
            wholeList = false;
            t0 = System.currentTimeMillis();
            try
            {
               //Go into overdrive
               adapter.setSpeed(adapter.SPEED_REGULAR);
               adapter.reset();
               adapter.putByte(0x3c); //overdrive skip rom
               adapter.setSpeed(adapter.SPEED_OVERDRIVE);

               // Begin search for new buttons
               if(!next)
               {
                  wholeList = true;
                  next = adapter.findFirstDevice();
               }

               for(tmpID=-1, cIndex=0;
                        next && (tmpID==-1);
                              next=adapter.findNextDevice())
               {
                  tmpID = adapter.getAddressAsLong();
                  if(tmpID!=coprID)
                  {
                     temp[cIndex++] = tmpID;
                     for(int i=0; i<index; i++)
                     {
                        if(buttons[i] == tmpID)
                        {//been here all along
                           tmpID = -1;
                           i = index;
                        }
                     }

                     if(tmpID!=-1)
                     {
                        //populate address array
                        adapter.getAddress(address);
                     }
                  }
                  else
                     tmpID = -1;
               }

               //if we found a new button
               if(tmpID!=-1)
               {
                  //add it to the main list
                  buttons[index++] = tmpID;

                  //quite searching, we got one!
                  buttonSearch = false;
               }
               else if(wholeList)
               {
                  //went through whole list with nothing new
                  //update the main list of buttons
                  buttons = temp;
                  index = cIndex;

                  //might as well play nice, every once in a while
                  Thread.yield();

                  //if user presses the enter key, we'll quit and clean up nicely
                  applicationFinished = (System.in.available()>0);
               }
            }
            catch(Exception e)
            {
               if(DEBUG)
               {
                  IOHelper.writeLine("adapter hiccup while searching");
                  e.printStackTrace();
               }
            }
         }

         if(applicationFinished)
            continue;

         // ---------------------------------------------------------
         // 取引を遂行するPerform the transaction
         // ---------------------------------------------------------
         try
         {
            t1 = System.currentTimeMillis();

            //de-ref the user
            user = null;

            //check for button family code
            if((tmpID&0x18)==(byte)0x18)
            {
               //get transactions for ds1963s
               trans = debit18;
               owc18.setupContainer(adapter, address);
               if(user18.setiButton18(owc18))
               {
                  user = user18;
               }
            }

            if(user!=null)
            {
               System.out.println();
               System.out.println(user.toString());
               t2 = System.currentTimeMillis();
               if(trans.verifyUser(user))
               {
                  t3 = System.currentTimeMillis();
                  if(trans.verifyTransactionData(user))
                  {
                     t4 = System.currentTimeMillis();
                     if(!trans.executeTransaction(user, true))
                        System.out.println("Execute Transaction Failed");
                     t5 = System.currentTimeMillis();

                     System.out.println("  Debit Amount: $00.50");
                     System.out.print("User's balance: $");
                     int balance = trans.getParameter(SHADebit.USER_BALANCE);
                     System.out.println(Convert.toString(balance/100d, 2));

                  }
                  else
                     System.out.println("Verify Transaction Data Failed");
               }
               else
                  System.out.println("Verify User Authentication Failed");
            }
            else
               System.out.println("Not a SHA user of this service");

            System.out.print("Total time: ");
            System.out.println(t5-t0);
            System.out.print("Executing transaction took: ");
            System.out.println(t5-t4);
            System.out.print("Verifying data took: ");
            System.out.println(t4-t3);
            System.out.print("Verifying user took: ");
            System.out.println(t3-t2);
            System.out.print("Loading user data took: ");
            System.out.println(t2-t1);
            System.out.print("Finding user took: ");
            System.out.println(t1-t0);

            //report all errors
            if(trans.getLastError()!=0)
            {
               IOHelper.writeLine("Last Error Code: ");
               IOHelper.writeLine(trans.getLastError());
               if(trans.getLastError()==trans.COPROCESSOR_FAILURE)
               {
                  IOHelper.writeLine("COPR Error Code: ");
                  IOHelper.writeLine(copr.getLastError());
               }
            }
         }
         catch(Exception e)
         {
            System.err.println("Transaction failed!");
            e.printStackTrace();
         }
      }

      // --------------------------------------------------------------
      // 終了処理
      // --------------------------------------------------------------
      adapter.endExclusive();
      coprAdapter.endExclusive();
      authAdapter.endExclusive();
   }

   static Properties sha_properties = null;
   /**
    * 示されたonewireのプロパティを得る
    * 次の場所からプロパティを探す:
    *   System.properties(環境変数)の中
    *   カレントディレクトリの中のonewire.propertiesファイル
    *       あるいは < java.home >/lib/ (Desktop) or /etc/ (TINI)
    *   プロパティが 'onewire.adapter.default'あるいは'onewire.port.default'
    *     だとスマートである
    *
    * 入力: propName 読み込むプロパティの名前のstring
    *
    * 戻り値:  プロパティ値を表すstringかみつからなかった場合はnullを返す
    *          (onewire.adapter.defaultとonewire.port.defaultの
    *          プロパティが存在していなくとも次のオーバーロードで
    *           default値を返すこともできる)
    */
   public static String getProperty (String propName)
   {
      // first, try system properties
      try
      {
         String ret_str = System.getProperty(propName, null);
         if(ret_str!=null)
            return ret_str;
      }
      catch (Exception e)
      { ; }

      // if defaults not found then try sha.properties file
      if(sha_properties==null)
      {
         //try to load sha_propreties file
         FileInputStream prop_file = null;

         // loop to attempt to open the sha.properties file in two locations
         // .\sha.properties or \lib\sha.properties
         String path = "";

         for (int i = 0; i <= 1; i++)
         {

            // attempt to open the sha.properties file
            try
            {
               prop_file = new FileInputStream(path + "sha.properties");
               // attempt to read the onewire.properties
               try
               {
                  sha_properties = new Properties();
                  sha_properties.load(prop_file);
               }
               catch (Exception e)
               {
                  //so we remember that it failed
                  sha_properties = null;
               }
            }
            catch (IOException e)
            {
               prop_file = null;
            }

            // check to see if we now have the properties loaded
            if (sha_properties != null)
               break;

            // try the second path
            path = System.getProperty("java.home") + File.separator + "lib"
                   + File.separator;
         }
      }

      if(sha_properties==null)
      {
         IOHelper.writeLine("Can't find sha.properties file");
         return null;
      }
      else
      {
         Object ret = sha_properties.get(propName);
         if(ret==null)
            return null;
         else
            return ret.toString();
      }
   }

   public static String getProperty (String propName, String defValue)
   {
      String ret = getProperty(propName);
      return (ret==null) ? defValue : ret;
   }

   public static boolean getPropertyBoolean(String propName, boolean defValue)
   {
      String strValue = getProperty(propName);
      if(strValue!=null)
         defValue = Boolean.valueOf(strValue).booleanValue();
      return defValue;
   }


   public static byte[] getPropertyBytes(String propName, byte[] defValue)
   {
      String strValue = getProperty(propName);
      if(strValue!=null)
      {
         //only supports up to 128 bytes of data
         byte[] tmp = new byte[128];

         //split the string on commas and spaces
         StringTokenizer strtok = new StringTokenizer(strValue,", ");

         //how many bytes we got
         int i = 0;
         while(strtok.hasMoreElements())
         {
            //this string could have more than one byte in it
            String multiByteStr = strtok.nextToken();
            int strLen = multiByteStr.length();

            for(int j=0; j<strLen; j+=2)
            {
               //get just two nibbles at a time
               String byteStr
                  = multiByteStr.substring(j, Math.min(j+2, strLen));

               long lng = 0;
               try
               {
                  //parse the two nibbles into a byte
                  lng = Long.parseLong(byteStr, 16);
               }
               catch(NumberFormatException nfe)
               {
                  nfe.printStackTrace();

                  //no mercy!
                  return defValue;
               }

               //store the byte and increment the counter
               if(i<tmp.length)
                  tmp[i++] = (byte)(lng&0x0FF);
            }
         }
         if(i>0)
         {
            byte[] retVal = new byte[i];
            System.arraycopy(tmp, 0, retVal, 0, i);
            return retVal;
         }
      }
      return defValue;
   }
}