コプロセッサを初期化する(2)

接続チェックで問題が無ければ、以下を付け加えて完成です。バックがピンクの部分が付け加えるところです。
import com.dalsemi.onewire.utils.IOHelper;
import com.dalsemi.onewire.*;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;
import com.dalsemi.onewire.application.sha.*;
import java.util.Vector;
import java.io.*;
import com.dalsemi.onewire.utils.*;
import java.util.*;


public class initcopr
{
   static boolean EMULATE_COPR = false;
   static String SHA_COPR_FILENAME = "sha_copr";

   final static byte[] DEFAULT_COPR_ROMID
      = new byte[]{(byte)0x18,(byte)0xFB,(byte)0x13,0,0,0,0,(byte)0xB2};
ここからmainメソッドが始まる。

   /**
    * Method main
    *
    *
    * 入力: args
    *
    * OneWireExceptionをthrowする
    * OneWireIOExceptionをthrowsする
    *
    */
    public static void main (String[] args)
       throws OneWireIOException, OneWireException, IOException
    {
// プロパティファイル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;
        }
プロパティファイルの構成の簡単な説明
  1. #あるいは!で始まる行はコメントである
  2. 行の始めのスペースを除いて英文字で始まって数字も含まれるものが変数
  3. 区切りはスペースか=か:である。
  4. 次の英文字で始まって数字も含まれるものが値となる
コプロセッサのコンテナを初期化する
      // ------------------------------------------------------------
      // コプロセッサのコンテナを初期化する
      // ------------------------------------------------------------
      SHAiButtonCopr copr = null;
      OneWireContainer18 copr18 = new OneWireContainer18();
      copr18.setSpeed(DSPortAdapter.SPEED_OVERDRIVE, false);
      copr18.setSpeedCheck(false);
OneWireContainer18クラスはこの実験で用いるSHAのiButton1963Sに対応する クラスである。このクラスは1963Sをコントロールするメソッドなどを持っている。

コプロセッサに対するアダプタを設定する。

      // ------------------------------------------------------------
      // コプロセッサに対するアダプタを設定する
      // ------------------------------------------------------------
      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);    // 1963Sのみを探すようにする
         coprAdapter.beginExclusive(true);  // 排他制御ON
         coprAdapter.reset();
         coprAdapter.setSearchAllDevices();// Alarm状態も解除して探す
         coprAdapter.reset();
         coprAdapter.putByte(0x3c);
         coprAdapter.setSpeed(coprAdapter.SPEED_OVERDRIVE);//高速度に設定
      }
      catch(Exception e)
      {
         IOHelper.writeLine("Error initializing coprocessor adapter");
         e.printStackTrace();
         System.exit(1);
      }
  (1)のmainメソッドの最後に下記を挿入する。つまり、下記はmainメソッドの続き

      // ---------------------------------------------------------
      // Get the name of the coprocessor service file
      // ---------------------------------------------------------
      String filename = getProperty("copr.filename","COPR.0");

      boolean next = false;
      boolean vmSaveSecrets = true;
      String coprVMfilename = null;
      // ------------------------------------------------------------
      // Find the coprocessor
      // ------------------------------------------------------------
      if(getPropertyBoolean("copr.simulated.isSimulated", false))
      {
         coprVMfilename = getProperty("copr.simulated.filename");
         vmSaveSecrets = getPropertyBoolean("copr.simulated.saveSecrets",true);
         // ---------------------------------------------------------
         // Load emulated coprocessor
         // ---------------------------------------------------------
         System.out.println("Setting up simulated Copressor.");
         System.out.println("Would you like to emulate another coprocessor? (y)");
         if(IOHelper.readLine().toUpperCase().charAt(0)=='Y')
         {
            OneWireContainer18 ibc = new OneWireContainer18();
            ibc.setSpeedCheck(false);
            try
            {
               next = coprAdapter.findFirstDevice();
               while(next && copr==null)
               {
                  try
                  {
                     System.out.println(coprAdapter.getAddressAsLong());
                     ibc.setupContainer(coprAdapter, coprAdapter.getAddressAsLong());
                     copr = new SHAiButtonCopr(ibc, filename);
                  }
                  catch(Exception e){e.printStackTrace();}
                  next = coprAdapter.findNextDevice();
               }
            }
            catch(Exception e){;}
            if(copr==null)
            {
               System.out.println("No coprocessor found to emulate");
               return;
            }

            System.out.println();
            System.out.println("Emulating Coprocessor: "+ibc.getAddressAsString());
            System.out.println();

            //now that we got all that, we need a signing secret and an authentication secret
            System.out.println(
               "How would you like to enter the signing secret (unlimited bytes)? ");
            byte[] sign_secret = getBytes(0);
            IOHelper.writeBytes(sign_secret);

            System.out.println();
            System.out.println(
               "How would you like to enter the authentication secret (unlimited bytes)? ");
            byte[] auth_secret = getBytes(0);
            IOHelper.writeBytes(auth_secret);

            System.out.println();
            if(copr.isDS1961Scompatible())
            {
               //reformat the auth_secret
               auth_secret = SHAiButtonCopr.reformatFor1961S(auth_secret);
               IOHelper.writeBytes(auth_secret);
            }
            System.out.println();
            copr = new SHAiButtonCoprVM(ibc, filename, sign_secret, auth_secret);

            ((SHAiButtonCoprVM)copr).save(coprVMfilename, true);

            System.out.println(copr);
            return;
         }

      }
      else
      {
         // ---------------------------------------------------------
         // Check for hardcoded coprocessor address
         // ---------------------------------------------------------
         byte[] coprAddress = getPropertyBytes("copr.address",null);
         long lookupID = 0, coprID = -1;
         if(coprAddress!=null)
         {
            lookupID = Address.toLong(coprAddress);

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

         // ---------------------------------------------------------
         // Find hardware coprocessor
         // ---------------------------------------------------------
         try
         {
            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);

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

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

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

         System.out.println("Setting up DS1963S as Coprocessor: " +
               Address.toString(copr18.getAddress()));
      }
      // Now that we've got a suitable button for creating a coprocessor,
      // let's ask the user for all the necessary paramters.

      System.out.print(
         "Enter the name of the coprocessor file (usually 'COPR') : ");
      byte[] coprname = IOHelper.readBytesAsc(4,' ');

      System.out.print(
         "Enter the file extension of the coprocessor file (0) : ");
      int coprext = IOHelper.readInt(0);

      System.out.print(
         "Enter the name of the service file (4 characters) : ");
      byte[] name = IOHelper.readBytesAsc(4,' ');

      System.out.print(
         "Enter the file extension of the service file (102 for Money) : ");
      byte ext = (byte)IOHelper.readInt(102);

      System.out.print("Enter authentication page number (7) : ");
      int auth_page = IOHelper.readInt(7);
      if (auth_page < 7)
      {
         System.out.println("Authentication page too low, default to 7");
         auth_page = 7;
      }
      if (auth_page == 8)
      {
         System.out.println("Page already taken, default to 7");
         auth_page = 7;
      }

      System.out.print("Enter workspace page number (9) : ");
      int work_page = IOHelper.readInt(9);
      if (work_page < 7)
      {
         System.out.println("Workspace page too low, default to 9");
         work_page = 9;
      }
      if ((work_page == 8) || (work_page == auth_page))
      {
         System.out.println("Page already taken, default to 9");
         work_page = 9;
      }

      System.out.print("Enter version number (1) : ");
      int  version = IOHelper.readInt(1);

      System.out.println(
         "How would you like to enter the binding data (32 bytes)? ");
      byte[] bind_data = getBytes(32);

      System.out.println(
         "How would you like to enter the binding code (7 bytes)? ");
      byte[] bind_code = getBytes(7);

      // This could be done on the button
      //java.util.Random random = new java.util.Random();
      //random.nextBytes(chlg);
      //  Need to know what the challenge is so that I can reproduce it!
      byte[] chlg = new byte []{0x00,0x00,0x00};

      System.out.println("Enter a human-readable provider name: ");
      String provider_name = IOHelper.readLine();

      System.out.println(
         "Enter an initial signature in HEX (all 0' default): ");
      byte[] sig_ini  = IOHelper.readBytesHex(20, 0);

      System.out.println(
         "Enter any additional text you would like store on the coprocessor: ");
      String aux_data = IOHelper.readLine();

      System.out.println("Enter an encryption code (0): ");
      int enc_code = IOHelper.readInt(0);

      //now that we got all that, we need a signing secret and an authentication secret
      System.out.println(
         "How would you like to enter the signing secret (unlimited bytes)? ");
      byte[] sign_secret = getBytes(0);
      IOHelper.writeBytes(sign_secret);

      System.out.println();
      System.out.println(
         "How would you like to enter the authentication secret (unlimited bytes)? ");
      byte[] auth_secret = getBytes(0);
      IOHelper.writeBytes(auth_secret);

      System.out.println();
      System.out.println(
         "Would you like to reformat the authentication secret for the 1961S? (y or n)");
      String s = IOHelper.readLine();
      if(s.toUpperCase().charAt(0)=='Y')
      {
         //reformat the auth_secret
         auth_secret = SHAiButtonCopr.reformatFor1961S(auth_secret);
         IOHelper.writeLine("authentication secret");
         IOHelper.writeBytes(auth_secret);
         IOHelper.writeLine();
      }

      // signing page must be 8, using secret 0
      int sign_page = 8;

      if(coprVMfilename!=null)
      {
         byte[] RomID = new byte[]
           { (byte)0x18,(byte)0x20,(byte)0xAF,(byte)0x02,
             (byte)0x00,(byte)0x00,(byte)0x00,(byte)0xE7 };
         RomID = getPropertyBytes("copr.simulated.address",RomID);

         copr = new SHAiButtonCoprVM(RomID,
                   sign_page, auth_page, work_page, version, enc_code,
                   ext, name, provider_name.getBytes(), bind_data, bind_code,
                   aux_data.getBytes(), sig_ini, chlg,
                   sign_secret, auth_secret);
         ((SHAiButtonCoprVM)copr).save(coprVMfilename, vmSaveSecrets);
      }
      else
      {
         String coprFilename = new String(coprname) + "." + coprext;
         // initialize this OneWireContainer18 as a valid coprocessor
         copr = new SHAiButtonCopr(copr18, coprFilename, true,
                   sign_page, auth_page, work_page, version, enc_code,
                   ext, name, provider_name.getBytes(), bind_data, bind_code,
                   aux_data.getBytes(), sig_ini, chlg,
                   sign_secret, auth_secret);
      }
      System.out.println("Initialized Coprocessor");
      System.out.println(copr.toString());

      System.out.println("done");
   }
mainメソッド終了

   public static byte[] getBytes(int cnt)
   {
      System.out.println("   1 HEX");
      System.out.println("   2 ASCII");
      System.out.print("  ? ");
      int choice = IOHelper.readInt(2);

      if(choice==1)
         return IOHelper.readBytesHex(cnt,0x00);
      else
         return IOHelper.readBytesAsc(cnt,0x00);
   }
  1. プロパティリストからcopr.adapterという変数を探し、その値を得る。
  2. 同様にcopr.portを探し、その値を得る。
  3. 実際にはTINIにはここに書かれているadapterはportはTINIExternalAdapterで portはserial1でなければいけない。
   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は
    *          プロパティが存在していなくとも'smart'を返す。
    */
   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<java.home>\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;
   }

}
注: nibbleは4bitの単位「ニブル」

以上をコンパイルしてTINIで実行する。