/*****************************************************************************************
*  Copyright (c) 2004, Beijing Senselock Data Security Centre
*  All rights reserved.
*
*  Filename£ºsample_25_win32.c
*          
*  Briefs£º  The purpose of this snippet is to demonstrate how to adjust double-precision float
*            calculation to avoid errors.
*            
*  History:        
*  --------------------------------------------------------        
*            10/28/2004 v1.0.0.0 Lihua created
*            
*            
*******************************************************************************************/

#include <stdio.h>
#include <conio.h>
#include <assert.h>
#include <float.h>
#include <math.h>

#include "..\..\inc\win32\sense4.h"
#include "..\..\inc\win32\crypt2.h"
#include "..\..\inc\win32\ses_err_msg.h"/* for debug purpose only */
#include "..\..\common\common.h"

#ifdef WIN32
#define  DOUBLE_T double
#endif

#include "..\inc\sample_25.h"


/* global variables definition */
SENSE4_CONTEXT stS4Ctx = {0};
unsigned long dwResult = 0;
unsigned long dwBytesReturned = 0;

IO_PACKAGE stDataPkgIn = {0};
IO_PACKAGE stDataPkgOut = {0};

#define S4_EXE_FILE_ID "ef25"
#define PI 3.1415926535
/* for debug purpose only : handle results returned by stDataPkgOut.tag */
#ifdef _DEBUG
void HandleError(unsigned char bErrCode, unsigned char *pbErrInfo)
{
	switch(bErrCode)
	{
	case ERR_SUCCESS:
		printf("Success!\n");
		break;
	case ERR_SES:
		printf("Error during SES Execution :\n%s\n", SesErrMsgs[*pbErrInfo]);
		break;
	case ERR_INVALID_PARAMETER:
		printf("Invalid input,pls check your input data\n");
		break;
	default:
		printf("Undefined error code!\n");
		break;
	}
	return;
}
#else
void HandleError(unsigned char bErrCode, unsigned char *pbErrInfo)
{
	return;
}	
#endif

/* check result for S4Execute(...) */
unsigned long CheckS4ExecutionResult(unsigned long dwResult,unsigned long dwBytesReturned,unsigned char tag)
{
	
	if (dwResult != S4_SUCCESS) 
	{
		printf("S4 Execution failed! <error code: 0x%08x>\n", dwResult);
		return 0;
	}
	
	if (dwBytesReturned < 2)
	{
		printf("Invalid data package returned!\n");
		return 0;
	}
	
	if (tag != ERR_SUCCESS)
	{
		HandleError(stDataPkgOut.tag, stDataPkgOut.buff);
		return 0;
	}
	return 1;
}


int main(int argc, char* argv[])
{
	typedef struct _DOUBLE_T_1
	{
		BYTE	mantL0;
		BYTE	mantL1;
		BYTE	mantL2;
		BYTE	mantL3;
		BYTE	mantH0;
		BYTE	mantH1;
		BYTE	mantH2:4, expL:4;
		BYTE	expH:7,   sign:1;
	}DOUBLE_T_1;
	//DOUBLE_T_1 dbl_epsilon = {0x00,0x00,0x00,0x00,0x00,0x00,0xB0,0x3C};
	unsigned char lpUserPin[8] = "12345678";
    DATA_BLOCK stDataBlk = {0};
	double cos_result = 0;
	double operand = 0;
	double bias = 0;
	double dbl = DBL_EPSILON;
	DOUBLE_T_1 *pdbl = (DOUBLE_T_1 *)&dbl;
				
	const DOUBLE_T dbl_const_1 = 1;
	pdbl = (DOUBLE_T_1 *)&dbl_const_1;

    if (!(dwResult = OpenS4ByIndex(FIRST_S4_INDEX,&stS4Ctx)))
	{
		return 1;
	}   
	
	dwResult = S4ChangeDir(&stS4Ctx, "\\");
	if (dwResult != S4_SUCCESS) 
	{
		printf("Change directory failed! <error code: 0x%08x>\n",dwResult);
		S4Close(&stS4Ctx);
		return dwResult;
	}
	
	// Call S4VerifyPin(...) to verify User PIN so as to get the privilege to execute the program in SenseLock EL.
	dwResult = S4VerifyPin(&stS4Ctx, lpUserPin, sizeof(lpUserPin), S4_USER_PIN);
	if (dwResult != S4_SUCCESS) 
	{
		printf("Verify Pin failed! <error code: 0x%08x>\n",dwResult);
		S4Close(&stS4Ctx);
		return dwResult;
	}	
	
	stDataBlk.cmd = CMD_DBL_COS;
	stDataBlk.operand = operand;
	stDataPkgIn.tag = 0; /* no meaning */
	stDataPkgIn.len = sizeof(DATA_BLOCK);
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);

	printf("Running SenseLock EL EXF %s...\n", S4_EXE_FILE_ID);
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len, 
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		ResetAndCloseS4(&stS4Ctx);
		return 1;
	}
	printf("Success!\n");	
	printf("The result:_cos(%.10f) = %.10f\n", operand, *((double *)stDataPkgOut.buff));
	
	/* if no adjustment, there will be unexpected wrong result */
	stDataBlk.cmd = CMD_DBL_ACOS;
	memcpy(&stDataBlk.operand, stDataPkgOut.buff, sizeof(double));
	stDataPkgIn.tag = 0; /* no meaning */
	stDataPkgIn.len = sizeof(DATA_BLOCK);
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);
	
	printf("Running SenseLock EL EXF %s...\n", S4_EXE_FILE_ID);
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len, 
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		ResetAndCloseS4(&stS4Ctx);
		return 1;
	}
	printf("Success!\n");	
	
	printf("Unexpected wrong result: _acos(_cos(%.10f)) = %.10f\n", operand, *((double *)stDataPkgOut.buff));
	
    /* adjustment */
	bias  = fabs(operand) - (int)(fabs(operand) / (2*PI))*2*PI;
	if ( bias < DBL_EPSILON)
	{
		cos_result = 1;
	}
	else if (fabs(bias - PI/2) < DBL_EPSILON)
	{
		cos_result = 0;
	}
	else if (fabs(bias - PI) < DBL_EPSILON)
	{
		cos_result = -1;
	}
	else if (fabs(bias - PI*3/2) < DBL_EPSILON)
	{
		cos_result = 0;
	}
	
	stDataBlk.cmd = CMD_DBL_ACOS;
	stDataBlk.operand = cos_result;
	stDataPkgIn.tag = 0; /* no meaning */
	stDataPkgIn.len = sizeof(DATA_BLOCK);
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);
	
	printf("Running SenseLock EL EXF %s...\n", S4_EXE_FILE_ID);
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len, 
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		ResetAndCloseS4(&stS4Ctx);
		return 1;
	}
	printf("Success!\n");	
	printf("The correct result after adjustment:_acos(_cos(%.10f)):%.10f\n", operand, *((double *)stDataPkgOut.buff));
	
	/* for better security,use the following instead of using S4close() directly */
 	ResetAndCloseS4(&stS4Ctx);
	getch();

	return dwResult;
}





















