//---------------------------------------------------------------------------
// Copyright (C) 2001 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.
//--------------------------------------------------------------------------
//
//  jibmodpw.c - test teh  a JiBLet TestModPow on a Java Powered iButton
//
//  version 3.00 Beta
//

#include "jib96.h"
#include <string.h>
#include <time.h>
#include "ownet.h"

#define MAXDEVICES 10
#define LOAD_UNLOAD_TIME  500
#define EXECUTE_TIME      1500

// external functions
extern SMALLINT  FindDevices(int,uchar FamilySN[][8],SMALLINT,int);
extern void      PrintSerialNum(uchar*);
extern int       key_abort(void);

// local prototypes
uchar *getRandData(uchar  p_Len, uchar *p_lpData);
uchar CycleTest(int portnum, uchar *dev);

// globals
int     g_NumCompletions  = 0,
        g_NumFailures     = 0;

//--------------------------------------------------------------------------
// Main for the Jib test
//
int main(int argc, char **argv)
{
   int i, portnum=0, NumDevices;
   uchar FamilySN[MAXDEVICES][8];

   // check for required port name
   if (argc != 2)
   {
      printf("1-Wire Net name required on command line!\n"
             " (example: \"COM1\" (Win32 DS2480),\"/dev/cua0\" "
             "(Linux DS2480),\"1\" (Win32 TMEX)\n");
      exit(1);
   }

   // attempt to acquire the 1-Wire Net
   if ((portnum = owAcquireEx(argv[1])) < 0)
   {
      OWERROR_DUMP(stdout);
      exit(1);
   }

   // success
   printf("Port opened: %s\n",argv[1]);

   // initialize the random number generator
   srand((unsigned)time(NULL));

   // Find the device(s)
   NumDevices = FindDevices(portnum, &FamilySN[0], 0x16, MAXDEVICES);

   if (NumDevices>0)
   {
      printf("\n");
      printf("JiB(s) Found: \n");
      for (i = 0; i < NumDevices; i++)
      {
         PrintSerialNum(FamilySN[i]);
         printf("\n");
      }
      printf("\n\n");

      do
      {
          // loop through the devices and do a test on each
         for (i = 0; i < NumDevices; i++)
            CycleTest(portnum, FamilySN[i]);
      }
      while (!key_abort());
   }
   else
      printf("No JiB's Found!\n");

   // release the 1-Wire Net
   owRelease(portnum);
   printf("Closing port %s.\n", argv[1]);
   exit(0);
   return 0;
}

//--------------------------------------------------------------------------
// Get random numbers
//
uchar *getRandData(uchar  p_Len, uchar *p_lpData)
{
  int i;
  p_lpData[0] =  p_Len;

  for(i = 1; i <= p_Len; i++)
    p_lpData[i] = (uchar)rand();

  p_lpData[1] |= 0x80;
  return p_lpData;
}

//--------------------------------------------------------------------------
// This is a simple function to verify the coprocessor functions using
// the JiBlet TestModExp.jib.
// NOTE: TestModExp must be loaded and selected before executing this function.
//
uchar CycleTest(int portnum, uchar *dev)
{

   LPRESPONSEAPDU  l_lpResponseAPDU;
   uchar           l_RefBuffer[256];
   uchar           l_Message[129],
                   l_Modulus[129],
                   l_Exponent[129];
   uchar           l_i;

   // select the device and put in overdrive
   printf("\nDevice: ");
   PrintSerialNum(dev);
   printf("\n");

   owSerialNum(portnum,dev,0);
   if (!owOverdriveAccess(portnum))
      printf("ERROR, could not get device in overdrive!\n");

   // read the firmware string //
   l_lpResponseAPDU = GetFirmwareVersionString(portnum);

   if(l_lpResponseAPDU)
   {
      if(l_lpResponseAPDU->SW == (ushort)0x9000)
      {
         // trim out the length byte //
         memcpy(l_RefBuffer,l_lpResponseAPDU->Data+1,l_lpResponseAPDU->Len-1);

         // zero terminate the string //
         l_RefBuffer[l_lpResponseAPDU->Len-1] = 0;
         printf("Firmware: %s\n",l_RefBuffer);
      }
      else
         printf("GetFirmwareVersionString Error: SW = %4.4X",l_lpResponseAPDU->SW);
   }

   printf("Loading Message\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x00, 0, 0, 128, getRandData(127,l_Message), LOAD_UNLOAD_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Load Message failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   printf("Loading Exponent\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x01, 0, 0, 128, getRandData(127,l_Exponent), LOAD_UNLOAD_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Load Exponent failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   // make the modulus 1 byte larger than the exponent and message to insure that it is larger
   // without actually doing a "big number" compare (a quick cheat).
   printf("Loading Modulus\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x02, 0, 0, 129, getRandData(128,l_Modulus), LOAD_UNLOAD_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Load Modulus failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   printf("Performing Exponentiation\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x03, 0, 0, 0, NULL, EXECUTE_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Exponentiation failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   printf("Performing Read\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x04, 0, 0, 0, NULL, LOAD_UNLOAD_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Read failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   memcpy(l_RefBuffer,l_lpResponseAPDU->Data,l_lpResponseAPDU->Len);

   printf("Performing Verification\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x03, 0, 0, 0, NULL, EXECUTE_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Verification failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   printf("Performing Verification Read\n");
   l_lpResponseAPDU = Process(portnum, 0x80, 0x04, 0, 0, 0, NULL, LOAD_UNLOAD_TIME);

   if(l_lpResponseAPDU->SW != (ushort)0x9000)
   {
      printf("Read failed with SW = %04x\n",l_lpResponseAPDU->SW);
      return FALSE;
   }

   printf("Result: ");

   for(l_i = 0; l_i < l_lpResponseAPDU->Len; l_i++)
   {
    if(!(l_i%16))
      printf("\n");

    printf("%02X ",l_lpResponseAPDU->Data[l_i]);
   }

   printf("\n");
   g_NumCompletions++;

   if(!memcmp(l_RefBuffer,l_lpResponseAPDU->Data,l_lpResponseAPDU->Len))
   {
      printf("Buffer matches reference\nCompleted Iterations: %d, Failures: %d, Percent Failures: %2.2f\n",
              g_NumCompletions,g_NumFailures,(double)g_NumFailures/g_NumCompletions*100);
   }
   else
   {
      printf("Buffer does NOT match reference\nIterations: %d, Failures: %d\n",g_NumCompletions,++g_NumFailures);
   }

   return TRUE;
}

