
/*---------------------------------------------------------------------------
 * Copyright (C) 1999,2000 Dallas Semiconductor Corporation, All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dallas Semiconductor
 * shall not be used except as stated in the Dallas Semiconductor
 * Branding Policy.
 *---------------------------------------------------------------------------
 */

import com.dalsemi.onewire.*;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;
import java.util.Vector;
import java.io.*;
import com.dalsemi.onewire.utils.CRC16;
import java.util.*;


public class initrov
{
   static byte[] page0 =
   {
      ( byte ) 0x0F, ( byte ) 0xAA, ( byte ) 0x00, ( byte ) 0x80,
      ( byte ) 0x03, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
      ( byte ) 0x43, ( byte ) 0x4F, ( byte ) 0x50, ( byte ) 0x52,
      ( byte ) 0x00, ( byte ) 0x01, ( byte ) 0x01, ( byte ) 0x00,
      ( byte ) 0x74, ( byte ) 0x9C, ( byte ) 0xFF, ( byte ) 0xFF,
      ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
      ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
      ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF
   };

   static byte[] parse (BufferedReader in, int count, int pad,
                        boolean hex_ify_it)
   {
      try
      {
         String s   = in.readLine();
         int    len = s.length() > count ? count
                                         : s.length();
         byte[] ret;

         if (count > 0)
            ret = new byte [count];
         else
            ret = new byte [s.length()];

         if (hex_ify_it)
         {
            byte[] temp = readHex(s, 0);

            if (count == 0)
               return temp;

            len = temp.length;

            System.arraycopy(temp, 0, ret, 0, len);
         }
         else
         {
            if (count == 0)
            {
               System.arraycopy(s.getBytes(), 0, ret, 0, s.length());

               return ret;
            }

            System.arraycopy(s.getBytes(), 0, ret, 0, len);
         }

         for (; len < count; len++)
            ret [len] = ( byte ) pad;

         return ret;
      }
      catch (Exception e)
      {
         return new byte [count];
      }
   }

   static int parseInt (BufferedReader in, int def)
   {
      try
      {
         return Integer.parseInt(in.readLine());
      }
      catch (Exception e)
      {
         return def;
      }
   }

   /**
    * Method printUsageString
    *
    *
    */
   public static void printUsageString ()
   {
      System.out.println(
         "DS1963S SHA iButton Java Demo Transaction Program.\r\n");
      System.out.println("Usage: ");
      System.out.println("   java initrov ADAPTER_PORT\r\n");
      System.out.println(
         "ADAPTER_PORT is a String that contains the name of the");
      System.out.println(
         "adapter you would like to use and the port you would like");
      System.out.println("to use, for example: ");
      System.out.println("   java initrov {DS1410E}_LPT1");
      System.out.println(
         "You can leave ADAPTER_PORT blank to use the default one-wire adapter and port.");
   }

   /**
    * Method main
    *
    *
    * @param args
    *
    * @throws OneWireException
    * @throws OneWireIOException
    *
    */
   public static void main (String[] args)
      throws OneWireIOException, OneWireException
   {
      byte[]        ID         = new byte [8];
      byte[]        filebuffer = new byte [400];
      int           filelength;
      int           i;
      long[]        buttons      = new long [10];
      int           index        = 0;
      DSPortAdapter access       = null;
      long          coprocessor  = 0;
      SHAiButton    copr         = null;
      boolean       usedefault   = false;
      String        adapter_name = null;
      String        port_name    = null;

      if ((args == null) || (args.length < 1))
      {
         try
         {
            access = OneWireAccessProvider.getDefaultAdapter();

            if (access == null)
               throw new Exception();
         }
         catch (Exception e)
         {
            System.out.println("Couldn't get default adapter!");
            printUsageString();

            return;
         }

         usedefault = true;
      }

      if (!usedefault)
      {
         StringTokenizer st = new StringTokenizer(args [0], "_");

         if (st.countTokens() != 2)
         {
            printUsageString();

            return;
         }

         adapter_name = st.nextToken();
         port_name    = st.nextToken();

         System.out.println("Adapter Name: " + adapter_name);
         System.out.println("Port Name: " + port_name);
      }

      if (access == null)
      {
         try
         {
            access = OneWireAccessProvider.getAdapter(adapter_name,
                                                      port_name);
         }
         catch (Exception e)
         {
            System.out.println(
               "That is not a valid adapter/port combination.");

            Enumeration en = OneWireAccessProvider.enumerateAllAdapters();

            while (en.hasMoreElements())
            {
               DSPortAdapter temp = ( DSPortAdapter ) en.nextElement();

               System.out.println("Adapter: " + temp.getAdapterName());

               Enumeration f = temp.getPortNames();

               while (f.hasMoreElements())
               {
                  System.out.println("   Port name : "
                                     + (( String ) f.nextElement()));
               }
            }

            return;
         }
      }

      access.adapterDetected();
      access.targetFamily(0x18);
      access.beginExclusive(true);
      access.reset();
      access.setSearchAllDevices();

      boolean next = access.findFirstDevice();

      if (copr == null)
         while (next)
         {
            access.getAddress(ID);

            OneWireContainer18 ds1963S =
               ( OneWireContainer18 ) access.getDeviceContainer(ID);

            ds1963S.setupContainer(access, ID);
            ds1963S.setSpeedCheck(false);

            SHAiButton sha = new SHAiButton(ds1963S);

            filelength = sha.readFile(0, filebuffer);

            //look for file COPR.000
            byte[] file     = "COPR".getBytes();
            int    filepage = -1;

            buttons [index] = access.getAddressAsLong();

            index++;

            for (i = 0; i < filelength; i++)
            {
               if (filebuffer [i] == file [0])
                  if (filebuffer [i + 1] == file [1])
                     if (filebuffer [i + 2] == file [2])
                        if (filebuffer [i + 3] == file [3])
                           if (filebuffer [i + 4] == ( byte ) 0)   //000 is the extension
                              filepage = filebuffer [i + 5];
            }

            if (filepage == -1)
            {
               System.out.println("Couldnt find the file page!!!");
            }
            else
            {
               try
               {
                  filelength = sha.readFile(filepage, filebuffer);

                  sha.setFilename(filebuffer, 0);
                  sha.setSigningPageNumber(filebuffer [5]);
                  sha.setAuthenticationPageNumber(filebuffer [6]);
                  sha.setWorkspacePageNumber(filebuffer [7]);

                  if (filelength >= 45)
                     sha.setBindData(filebuffer, 13);

                  if (filelength >= 52)
                     sha.setBindCode(filebuffer, 45);
               }
               catch (Exception e)
               {
                  System.out.println("Exception getting all that data");
               }

               if (sha.isCoprocessor())
               {
                  coprocessor = ds1963S.getAddressAsLong();
                  copr        = sha;

                  System.out.println("Found a coprocessor for service \""
                                     + sha.getUserFileName() + "\"");

                  index--;   //take the coprocessor out of the list
               }
            }

            next = access.findNextDevice();
         }   //end while next

      access.targetFamily(0x18);

      if (copr == null)
      {
         System.out.println("Coprocessor is NULL!");

         return;   //exit
      }

      OneWireContainer18 ibc = new OneWireContainer18();

      ibc.setSpeedCheck(false);

      if (index > 0)
      {
         ibc.setupContainer(access, buttons [0]);
         System.out.println("Setting up roving iButton "
                            + Long.toHexString(buttons [0]));
      }
      else
      {
         System.out.println("Could not find any other iButtons!");

         return;
      }

      BufferedReader in  =
         new BufferedReader(new InputStreamReader(System.in));
      SHAiButton     sha = new SHAiButton(ibc);

      if (copr == null)
      {
         System.out.println("You must have a coprocessor!");

         return;
      }

      int auth_page = 13;
      int tid       = 0x1234;
      int fact      = 0x8b48;
      int data_type = 0;

      System.out.println(
         "How would you like to enter the authentication secret (unlimited bytes)? ");
      System.out.println("   1 HEX");
      System.out.println("   2 ASCII");
      System.out.print("  ? ");

      int    choice      = parseInt(in, 2);
      byte[] auth_secret = parse(in, 0, ((choice == 1) ? 0x00
                                                       : 0x20), (choice
                                                                 == 1));

      dump(auth_secret);

      if (!ibc.installMasterSecret(auth_page, auth_secret, auth_page & 7))
         System.out.println(
            "Could not install master authentication secret!");
      else
         System.out.println("Authentication secret installed.");

      //now we need to bind this data to the user ibutton
      if (!ibc.bindSecretToiButton(auth_page, copr.getBindData(),
                                   copr.getBindCode(), auth_page & 7))
      {
         System.out.println("Failed to bind the secret to the ibutton");
      }
      else
         System.out.println("Authentication secret bound to ibutton");

      byte[] default_page = new byte [32];

      default_page [1] = ( byte ) 0x34;
      default_page [2] = ( byte ) 0x12;
      default_page [3] = ( byte ) 0x48;
      default_page [4] = ( byte ) 0x8b;

      sha.setUser(auth_page);

      if (copr.signDataFile(sha, 10000, -1, default_page))
         System.out.println("Succesfully set up user iButton");
      else
         System.out.println("Failed to set up user iButton");

      char[] name = copr.getUserFileName().toCharArray();
      int    ext  = copr.getUserFileExtension();

      page0 [8]  = ( byte ) name [0];
      page0 [9]  = ( byte ) name [1];
      page0 [10] = ( byte ) name [2];
      page0 [11] = ( byte ) name [3];
      page0 [12] = ( byte ) ext;
      page0 [13] = ( byte ) auth_page;
      page0 [14] = ( byte ) 1;

      //the mask should represent that we are using page 0 and page auth_page
      int mask = 0x01 | (0x01 << auth_page);

      //now put that int (LSB first) in page0[4..7]
      page0 [4] = ( byte ) (mask);
      page0 [5] = ( byte ) (mask >> 8);
      page0 [6] = ( byte ) (mask >> 16);
      page0 [7] = ( byte ) (mask >> 24);

      //now redo the CRC and ship that baby!
      int CRC = ~CRC16.compute(page0, 0, page0 [0] + 1);

      page0 [page0 [0] + 1] = ( byte ) CRC;
      page0 [page0 [0] + 2] = ( byte ) (CRC >> 8);

      //now we have to fix page 0, there's a bitmap and a file length thing to fix    
      if ((!ibc.eraseScratchPad(0)) || (!ibc.writeDataPage(0, page0)))
      {
         System.out.println("Failed to write page 0");

         return;
      }
   }

   /**
    * Method help
    *
    *
    */
   public void help ()
   {
      System.out.println("command: wcc\r\n");
      System.out.println("Usage: coprocessor");
      System.out.println();
      System.out.println(
         "Displays the write cycle counter for page PAGE_NUM");
   }

   static char[] hex = "0123456789ABCDEF".toCharArray();

   /**
    * Method dump
    *
    *
    * @param A
    *
    */
   public static void dump (byte[] A)
   {
      StringBuffer sb   = new StringBuffer();
      int          last = 0;
      int          i    = 0;

      for (i = 0; i < A.length; i++)
      {
         if (((i & 15) == 0) && (i != 0))
         {
            sb.append("  ");

            for (int k = last; k < i; k++)
               sb.append(( char ) A [k]);

            sb.append("\r\n");

            last = i;
         }

         sb.append(hex [(A [i] >> 4) & 0x0f]);
         sb.append(hex [(A [i]) & 0x0f]);
         sb.append('.');
      }
      sb.append("  ");

      for (int k = last; k < i; k++)
         sb.append(( char ) A [k]);
      System.out.println(sb);
   }

   /**
    * Method dump
    *
    *
    * @param A
    * @param start
    * @param offset
    *
    */
   public static void dump (byte[] A, int start, int offset)
   {
      StringBuffer sb   = new StringBuffer();
      int          last = start;
      int          i    = start;

      for (i = start; i < start + offset; i++)
      {
         if ((((i - start) & 15) == 0) && (i != start))
         {
            sb.append("  ");

            for (int k = last; k < i; k++)
               sb.append(( char ) A [k]);

            sb.append("\r\n");

            last = i;
         }

         sb.append(hex [(A [i] >> 4) & 0x0f]);
         sb.append(hex [(A [i]) & 0x0f]);
         sb.append('.');
      }
      sb.append("  ");

      for (int k = last; k < i; k++)
         sb.append(( char ) A [k]);
      System.out.println(sb);
   }

   /**
    * Method readHex
    *
    *
    * @param s
    * @param size
    *
    * @return
    *
    */
   public static byte[] readHex (String s, int size)
   {
      int    index = 0;
      int    i     = 0;
      char[] x     = s.toLowerCase().toCharArray();
      byte[] temp;

      if (size > 0)
         temp = new byte [size];
      else
         temp = new byte [x.length];

      try
      {
         while ((i < x.length) && (index < (temp.length * 2)))
         {
            int  shift = ((index & 0x01) == 0x01) ? 0
                                                  : 4;
            char c     = x [i++];

            switch (c)
            {

               case '0' :
                  index++;   //special case--zero
                  break;
               case '1' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (1 << shift));

                  index++;
                  break;
               case '2' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (2 << shift));

                  index++;
                  break;
               case '3' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (3 << shift));

                  index++;
                  break;
               case '4' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (4 << shift));

                  index++;
                  break;
               case '5' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (5 << shift));

                  index++;
                  break;
               case '6' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (6 << shift));

                  index++;
                  break;
               case '7' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (7 << shift));

                  index++;
                  break;
               case '8' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (8 << shift));

                  index++;
                  break;
               case '9' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (9 << shift));

                  index++;
                  break;
               case 'a' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (10 << shift));

                  index++;
                  break;
               case 'b' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (11 << shift));

                  index++;
                  break;
               case 'c' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (12 << shift));

                  index++;
                  break;
               case 'd' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (13 << shift));

                  index++;
                  break;
               case 'e' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (14 << shift));

                  index++;
                  break;
               case 'f' :
                  temp [index >> 1] = ( byte ) (temp [index >> 1]
                                                | (15 << shift));

                  index++;
                  break;
            }
         }                   //end while
      }
      catch (Exception e)
      {
         return null;
      }

      if (size > 0)
         return temp;

      byte[] t = new byte [(index + 1) >> 1];

      System.arraycopy(temp, 0, t, 0, t.length);

      return t;
   }
}
