//---------------------------------------------------------------------------

#include <inifiles.hpp>
#include <registry.hpp>
#include <Classes.hpp>
#include <math.h>
#include "MultiLanguage.h"

#pragma hdrstop

#include "Common_PC.h"
#pragma package(smart_init)

#define MOTOR_ROUND_PER_VALUE	10
#define MECH_MOVE_PER_VALUE		140
//#define MOTOR_SPEED_STEP_COUNT			10

#define CURRENT_PRODUCT_DATA_MAJOR_VERSION		2
#define CURRENT_PRODUCT_DATA_MINOR_VERSION		0

#define min(x, y) (x < y ? x : y)

int Table_Interval_PixelAndMeter[1000]; //10um단위
int BackupSpeedMode;
//---------------------------------------------------------------------------
void __fastcall SetGrayPalette(Graphics::TBitmap *theBitmap)
{
	struct
	{
	    WORD        palVersion;
	    WORD        palNumEntries;
	    PALETTEENTRY        palPalEntry[256];
	} grayPalette;

    grayPalette.palVersion = 0x300;
    grayPalette.palNumEntries = 256;
    for (int i = 0; i < 256; i++)
    {
    	grayPalette.palPalEntry[i].peRed = i;
        grayPalette.palPalEntry[i].peGreen = i;
        grayPalette.palPalEntry[i].peBlue = i;
		grayPalette.palPalEntry[i].peFlags = 0;
    }
	PLOGPALETTE pLogPal = (PLOGPALETTE) &grayPalette;

    theBitmap->Palette = CreatePalette(pLogPal);
}
//---------------------------------------------------------------------------
void __fastcall Set3DPalette(Graphics::TBitmap *theBitmap)
{
	struct
	{
		WORD        palVersion;
		WORD        palNumEntries;
		PALETTEENTRY        palPalEntry[256];
	} grayPalette;

	grayPalette.palVersion = 0x300;
	grayPalette.palNumEntries = 256;
	for (int i = 0; i < 64; i++)
	{
		grayPalette.palPalEntry[i].peRed = 0;
		grayPalette.palPalEntry[i].peGreen = 0;
		grayPalette.palPalEntry[i].peBlue = i * 4 + 3;
		grayPalette.palPalEntry[i].peFlags = 0;
	}
	for (int i = 64; i < 128; i++)
	{
		grayPalette.palPalEntry[i].peRed = 0;
		grayPalette.palPalEntry[i].peGreen = i * 4 + 3;
		grayPalette.palPalEntry[i].peBlue = (127 - i) * 4 + 3;
		grayPalette.palPalEntry[i].peFlags = 0;
	}
	for (int i = 128; i < 192; i++)
	{
		grayPalette.palPalEntry[i].peRed = i * 4 + 3;
		grayPalette.palPalEntry[i].peGreen = 255;
		grayPalette.palPalEntry[i].peBlue = 0;
		grayPalette.palPalEntry[i].peFlags = 0;
	}
	for (int i = 192; i < 256; i++)
	{
		grayPalette.palPalEntry[i].peRed = 255;
		grayPalette.palPalEntry[i].peGreen = (255 - i) * 4 + 3;
		grayPalette.palPalEntry[i].peBlue = 0;
		grayPalette.palPalEntry[i].peFlags = 0;
	}
	PLOGPALETTE pLogPal = (PLOGPALETTE) &grayPalette;

	theBitmap->Palette = CreatePalette(pLogPal);
}
//---------------------------------------------------------------------------
double __fastcall Motor_RPM_To_MMPS(int rpm)
{
	return rpm * MECH_MOVE_PER_VALUE / MOTOR_ROUND_PER_VALUE / 10.0 / 60.0;
}
//---------------------------------------------------------------------------

bool __fastcall ReadMachineSetupData(AnsiString fileName, TMachineSetupData &machineSetupData)
{
	bool returnValue = true;
	memset(&machineSetupData, 0, sizeof(TMachineSetupData));
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		machineSetupData.MachineMode = iniFile->ReadInteger("Machine Info", "Machine Mode", MACHINE_MODE_TEST);
		machineSetupData.PC_Power_Mode = iniFile->ReadInteger("Power Info", "PC PowerMode", PC_POWER_MODE_AUTO);

		for (int captureIndex = 0; captureIndex < SYSTEM_MACHINE_CAPTURE_COUNT; captureIndex++)
		{
			machineSetupData.MachineCaptureInfo.CaptureDelay[captureIndex] = iniFile->ReadInteger("Machine Capture Info", "Capture Delay " + IntToStr(captureIndex), 0);
			machineSetupData.MachineCaptureInfo.IlluminatorMask[captureIndex] = iniFile->ReadInteger("Machine Capture Info", "Illuminator Mask " + IntToStr(captureIndex), 0);
			machineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex] = iniFile->ReadInteger("Machine Capture Info", "Illuminator Delay " + IntToStr(captureIndex), 0);
			machineSetupData.MachineCaptureInfo.IlluminatorTime[captureIndex] = iniFile->ReadInteger("Machine Capture Info", "Illuminator Time " + IntToStr(captureIndex), 0);
            machineSetupData.MachineCaptureInfo.CamMask[captureIndex] = iniFile->ReadInteger("Machine Capture Info", "Camera Map " + IntToStr(captureIndex), 0);
        }
//        machineSetupData.MachineCaptureInfo.CaptureStableDelay = iniFile->ReadInteger("Machine Capture Info", "Capture Stable Delay", 0);

        for (int sensorIndex = 0; sensorIndex < 2; sensorIndex++)
        {
        	machineSetupData.MachineCaptureInfo.SensorSPBMask[sensorIndex] = iniFile->ReadInteger("Machine Capture Info", "Sensor SPB Mask " + IntToStr(sensorIndex), 0);
        }

        machineSetupData.EjectorInfo.DefectEjectorDelay = iniFile->ReadInteger("Ejector Info", "Defect Ejector Delay", 0);
        machineSetupData.EjectorInfo.DefectSolDelay = iniFile->ReadInteger("Ejector Info", "Defect Sol Delay", 0);
		machineSetupData.EjectorInfo.DefectSolMinTime = iniFile->ReadInteger("Ejector Info", "Defect Sol Min Time", 10);
        machineSetupData.EjectorInfo.DefectSolInterval1 = iniFile->ReadInteger("Ejector Info", "Defect Sol Interval 1", 0);
        machineSetupData.EjectorInfo.DefectSolInterval2 = iniFile->ReadInteger("Ejector Info", "Defect Sol Interval 2", 0);
        machineSetupData.EjectorInfo.UnInsEjectorDelay = iniFile->ReadInteger("Ejector Info", "UnIns Ejector Delay", 0);
        machineSetupData.EjectorInfo.UnInsSolDelay = iniFile->ReadInteger("Ejector Info", "UnIns Sol Delay", 0);
        machineSetupData.EjectorInfo.UnInsSolMinTime = iniFile->ReadInteger("Ejector Info", "UnIns Sol Min Time", 10);
		machineSetupData.EjectorInfo.UnInsSolInterval1 = iniFile->ReadInteger("Ejector Info", "UnIns Sol Interval 1", 0);
		machineSetupData.EjectorInfo.UnInsSolInterval2 = iniFile->ReadInteger("Ejector Info", "UnIns Sol Interval 2", 0);

		machineSetupData.EjectorInfo.MisejectActive = iniFile->ReadInteger("Ejector Info", "Miseject Active", 1);
		machineSetupData.EjectorInfo.MisejectDelay = iniFile->ReadInteger("Ejector Info", "Miseject Delay", 100);
		machineSetupData.EjectorInfo.MisejectRunTime = iniFile->ReadInteger("Ejector Info", "Miseject Run Time", 2000);
		machineSetupData.EjectorInfo.MisejectActiveDelay = iniFile->ReadInteger("Ejector Info", "Miseject Active Delay", 0);

        machineSetupData.VFInfo.ManualModeSensorIndex = iniFile->ReadInteger("Vibration Feeder Info", "Manual Mode Sensor Index", 0);
        machineSetupData.VFInfo.ManualModeSensorActiveRatio = iniFile->ReadInteger("Vibration Feeder Info", "Manual Mode Sensor Active Ratio", 80);
//		machineSetupData.VFInfo.EmptySensorIndex = iniFile->ReadInteger("Vibration Feeder Info", "Empty Sensor Index", 0);
		machineSetupData.VFInfo.EmptySensorActiveRatio = iniFile->ReadInteger("Vibration Feeder Info", "Empty Sensor Active Ratio", 80);
//		machineSetupData.VFInfo.FullSensorIndex = iniFile->ReadInteger("Vibration Feeder Info", "Full Sensor Index", 1);
		machineSetupData.VFInfo.FullSensorActiveRatio = iniFile->ReadInteger("Vibration Feeder Info", "Full Sensor Active Ratio", 80);
        machineSetupData.VFInfo.StartSpeed = iniFile->ReadInteger("Vibration Feeder Info", "Statr Speed", 40);
		machineSetupData.VFInfo.MaxSpeedTrainingMode = iniFile->ReadInteger("Vibration Feeder Info", "Max Speed Training Mode", MAX_SPEED_TRAINING_MODE_AUTO);
		machineSetupData.VFInfo.ManualMaxSpeed = iniFile->ReadInteger("Vibration Feeder Info", "Manual Max Speed", 100);
		machineSetupData.VFInfo.MechanicalMinSpeed = iniFile->ReadInteger("Vibration Feeder Info", "Mechanical Min Speed", 100);
		machineSetupData.VFInfo.MechanicalMaxSpeed = iniFile->ReadInteger("Vibration Feeder Info", "Mechanical Max Speed", 100);

		machineSetupData.SensorIntervalA = iniFile->ReadInteger("Sensor Info", "Sensor Interval A", 0);
		machineSetupData.SensorIntervalB = iniFile->ReadInteger("Sensor Info", "Sensor Interval B", 0);

		machineSetupData.InterlockInfo.DoorInterlockEnabled = iniFile->ReadInteger("Interlock Info", "Door Enabled", 0);
		machineSetupData.InterlockInfo.NCInterlockAValue = iniFile->ReadInteger("Interlock Info", "NC Interlock A Value", 0);

		for (int stepMotorIndex = 0; stepMotorIndex < MAX_STEP_MOTOR_COUNT; stepMotorIndex++)
		{
			machineSetupData.ZeroPositionValue[stepMotorIndex] = iniFile->ReadFloat("NC Info", "NC Zero Pos " + IntToStr(stepMotorIndex + 1), 0);
		}

		machineSetupData.LEDControlInfo.EyeProtectionModeEnabled = iniFile->ReadInteger("LED Control Info", "Eye Protection Mode Enabled", 0);
		machineSetupData.LEDControlInfo.LEDOnTime = iniFile->ReadInteger("LED Control Info", "Eye Protection LED On Time", 3);
		machineSetupData.LEDControlInfo.LEDOffDelay = iniFile->ReadInteger("LED Control Info", "Eye Protection LED Off Delay", 17);

		machineSetupData.BuzzerInfo.BuzzerContinuousOn = iniFile->ReadBool("Buzzer Info", "Buzzer Continuous On", true) ? 1 : 0;
		machineSetupData.BuzzerInfo.BuzzerOnTime = iniFile->ReadInteger("Buzzer Info", "Buzzer On Time", 10);

		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			machineSetupData.ServoMotorData[motorIndex].BaseSpeed = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Base Speed", 100);
			machineSetupData.ServoMotorData[motorIndex].AccTime = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Acc Time", 1000);
			machineSetupData.ServoMotorData[motorIndex].DecTime = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Dec Time", 1000);
			machineSetupData.ServoMotorData[motorIndex].Dir = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Direction", 1);
		}

		machineSetupData.AlarmSetupInfo.PressureAlarmLevel = iniFile->ReadInteger("Alarm Level", "Pressure Alarm Level", 400);
		machineSetupData.AlarmSetupInfo.VacuumAlarmLevel1 = iniFile->ReadInteger("Alarm Level", "Vacuum Alarm Level 1", 0);
		machineSetupData.AlarmSetupInfo.VacuumAlarmLevel2 = iniFile->ReadInteger("Alarm Level", "Vacuum Alarm Level 2", 0);
		machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel1 = iniFile->ReadInteger("Alarm Level", "Temperature Alarm Level 1", 50);
		machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel2 = iniFile->ReadInteger("Alarm Level", "Temperature Alarm Level 2", 50);
		machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel3 = iniFile->ReadInteger("Alarm Level", "Temperature Alarm Level 3", 50);
		delete iniFile;
    }
    else
    {
    	machineSetupData.MachineMode = MACHINE_MODE_TEST;
        machineSetupData.PC_Power_Mode = PC_POWER_MODE_AUTO;

        for (int captureIndex = 0; captureIndex < SYSTEM_MACHINE_CAPTURE_COUNT; captureIndex++)
        {
			machineSetupData.MachineCaptureInfo.CaptureDelay[captureIndex] = 0;
            machineSetupData.MachineCaptureInfo.IlluminatorMask[captureIndex] = 0;
            machineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex] = 0;
            machineSetupData.MachineCaptureInfo.IlluminatorTime[captureIndex] = 0;
			machineSetupData.MachineCaptureInfo.CamMask[captureIndex] = 0;
        }
//        machineSetupData.MachineCaptureInfo.CaptureStableDelay = 0;

        for (int sensorIndex = 0; sensorIndex < 2; sensorIndex++)
        {
        	machineSetupData.MachineCaptureInfo.SensorSPBMask[sensorIndex] = 0;
        }

        machineSetupData.EjectorInfo.DefectEjectorDelay = 0;
		machineSetupData.EjectorInfo.DefectSolDelay = 0;
		machineSetupData.EjectorInfo.DefectSolMinTime = 10;
        machineSetupData.EjectorInfo.DefectSolInterval1 = 0;
        machineSetupData.EjectorInfo.DefectSolInterval2 = 0;
        machineSetupData.EjectorInfo.UnInsEjectorDelay = 0;
        machineSetupData.EjectorInfo.UnInsSolDelay = 0;
        machineSetupData.EjectorInfo.UnInsSolMinTime = 10;
        machineSetupData.EjectorInfo.UnInsSolInterval1 = 0;
		machineSetupData.EjectorInfo.UnInsSolInterval2 = 0;

		machineSetupData.EjectorInfo.MisejectActive = 1;
		machineSetupData.EjectorInfo.MisejectDelay = 100;
		machineSetupData.EjectorInfo.MisejectRunTime = 2000;
		machineSetupData.EjectorInfo.MisejectActiveDelay = 0;

        machineSetupData.VFInfo.ManualModeSensorIndex = 0;
        machineSetupData.VFInfo.ManualModeSensorActiveRatio = 80;
//		machineSetupData.VFInfo.EmptySensorIndex = 0;
		machineSetupData.VFInfo.EmptySensorActiveRatio = 80;
//		machineSetupData.VFInfo.FullSensorIndex = 1;
		machineSetupData.VFInfo.FullSensorActiveRatio = 80;
        machineSetupData.VFInfo.StartSpeed = 40;
		machineSetupData.VFInfo.MechanicalMinSpeed = 20;
		machineSetupData.VFInfo.MechanicalMaxSpeed = 255;

		machineSetupData.SensorIntervalA = 0;
		machineSetupData.SensorIntervalB = 0;

		machineSetupData.InterlockInfo.DoorInterlockEnabled = 0;
		machineSetupData.InterlockInfo.NCInterlockAValue = 0;
		
		machineSetupData.BuzzerInfo.BuzzerContinuousOn = true;
		machineSetupData.BuzzerInfo.BuzzerOnTime = 10;		

		machineSetupData.LEDControlInfo.EyeProtectionModeEnabled = 0;
		machineSetupData.LEDControlInfo.LEDOnTime = 3;
		machineSetupData.LEDControlInfo.LEDOffDelay = 17;

		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			machineSetupData.ServoMotorData[motorIndex].BaseSpeed = 100;
			machineSetupData.ServoMotorData[motorIndex].AccTime = 1000;
			machineSetupData.ServoMotorData[motorIndex].DecTime = 1000;
			machineSetupData.ServoMotorData[motorIndex].Dir = 1;
		}

		machineSetupData.AlarmSetupInfo.PressureAlarmLevel = 400;
		machineSetupData.AlarmSetupInfo.VacuumAlarmLevel1 = 0;
		machineSetupData.AlarmSetupInfo.VacuumAlarmLevel2 = 0;
		machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel1 = 50;
		machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel2 = 50;
		machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel3 = 50;
		returnValue = false;
    }
    return returnValue;
}
//---------------------------------------------------------------------------
void __fastcall WriteMachineSetupData(AnsiString fileName, TMachineSetupData &machineSetupData)
{
	TIniFile *iniFile = new TIniFile(fileName);
    if (iniFile)
	{
		iniFile->WriteInteger("Machine Info", "Machine Mode", machineSetupData.MachineMode);
        iniFile->WriteInteger("Power Info", "PC PowerMode", machineSetupData.PC_Power_Mode);

		for (int captureIndex = 0; captureIndex < SYSTEM_MACHINE_CAPTURE_COUNT; captureIndex++)
        {
	        iniFile->WriteInteger("Machine Capture Info", "Capture Delay " + IntToStr(captureIndex), machineSetupData.MachineCaptureInfo.CaptureDelay[captureIndex]);
            iniFile->WriteInteger("Machine Capture Info", "Illuminator Mask " + IntToStr(captureIndex), machineSetupData.MachineCaptureInfo.IlluminatorMask[captureIndex]);
			iniFile->WriteInteger("Machine Capture Info", "Illuminator Delay " + IntToStr(captureIndex), machineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]);
            iniFile->WriteInteger("Machine Capture Info", "Illuminator Time " + IntToStr(captureIndex), machineSetupData.MachineCaptureInfo.IlluminatorTime[captureIndex]);
            iniFile->WriteInteger("Machine Capture Info", "Camera Map " + IntToStr(captureIndex), machineSetupData.MachineCaptureInfo.CamMask[captureIndex]);
        }
//        iniFile->WriteInteger("Machine Capture Info", "Capture Stable Delay", machineSetupData.MachineCaptureInfo.CaptureStableDelay);

        for (int sensorIndex = 0; sensorIndex < 2; sensorIndex++)
        {
        	iniFile->WriteInteger("Machine Capture Info", "Sensor SPB Mask " + IntToStr(sensorIndex), machineSetupData.MachineCaptureInfo.SensorSPBMask[sensorIndex]);
        }

        iniFile->WriteInteger("Ejector Info", "Defect Ejector Delay", machineSetupData.EjectorInfo.DefectEjectorDelay);
        iniFile->WriteInteger("Ejector Info", "Defect Sol Delay", machineSetupData.EjectorInfo.DefectSolDelay);
        iniFile->WriteInteger("Ejector Info", "Defect Sol Min Time", machineSetupData.EjectorInfo.DefectSolMinTime);
        iniFile->WriteInteger("Ejector Info", "Defect Sol Interval 1", machineSetupData.EjectorInfo.DefectSolInterval1);
        iniFile->WriteInteger("Ejector Info", "Defect Sol Interval 2", machineSetupData.EjectorInfo.DefectSolInterval2);
        iniFile->WriteInteger("Ejector Info", "UnIns Ejector Delay", machineSetupData.EjectorInfo.UnInsEjectorDelay);
        iniFile->WriteInteger("Ejector Info", "UnIns Sol Delay", machineSetupData.EjectorInfo.UnInsSolDelay);
        iniFile->WriteInteger("Ejector Info", "UnIns Sol Min Time", machineSetupData.EjectorInfo.UnInsSolMinTime);
        iniFile->WriteInteger("Ejector Info", "UnIns Sol Interval 1", machineSetupData.EjectorInfo.UnInsSolInterval1);
		iniFile->WriteInteger("Ejector Info", "UnIns Sol Interval 2", machineSetupData.EjectorInfo.UnInsSolInterval2);

		iniFile->WriteInteger("Ejector Info", "Miseject Active", machineSetupData.EjectorInfo.MisejectActive);
		iniFile->WriteInteger("Ejector Info", "Miseject Delay", machineSetupData.EjectorInfo.MisejectDelay);
		iniFile->WriteInteger("Ejector Info", "Miseject Run Time", machineSetupData.EjectorInfo.MisejectRunTime);
		iniFile->WriteInteger("Ejector Info", "Miseject Active Delay", machineSetupData.EjectorInfo.MisejectActiveDelay);

        iniFile->WriteInteger("Vibration Feeder Info", "Manual Mode Sensor Index", machineSetupData.VFInfo.ManualModeSensorIndex);
        iniFile->WriteInteger("Vibration Feeder Info", "Manual Mode Sensor Active Ratio", machineSetupData.VFInfo.ManualModeSensorActiveRatio);
//		iniFile->WriteInteger("Vibration Feeder Info", "Empty Sensor Index", machineSetupData.VFInfo.EmptySensorIndex);
		iniFile->WriteInteger("Vibration Feeder Info", "Empty Sensor Active Ratio", machineSetupData.VFInfo.EmptySensorActiveRatio);
//		iniFile->WriteInteger("Vibration Feeder Info", "Full Sensor Index", machineSetupData.VFInfo.FullSensorIndex);
		iniFile->WriteInteger("Vibration Feeder Info", "Full Sensor Active Ratio", machineSetupData.VFInfo.FullSensorActiveRatio);
        iniFile->WriteInteger("Vibration Feeder Info", "Start Speed", machineSetupData.VFInfo.StartSpeed);
		iniFile->WriteInteger("Vibration Feeder Info", "Max Speed Training Mode", machineSetupData.VFInfo.MaxSpeedTrainingMode);
		iniFile->WriteInteger("Vibration Feeder Info", "Manual Max Speed", machineSetupData.VFInfo.ManualMaxSpeed);
		iniFile->WriteInteger("Vibration Feeder Info", "Mechanical Min Speed", machineSetupData.VFInfo.MechanicalMinSpeed);
		iniFile->WriteInteger("Vibration Feeder Info", "Mechanical Max Speed", machineSetupData.VFInfo.MechanicalMaxSpeed);

		iniFile->WriteInteger("Sensor Info", "Sensor Interval A", machineSetupData.SensorIntervalA);
		iniFile->WriteInteger("Sensor Info", "Sensor Interval B", machineSetupData.SensorIntervalB);

		iniFile->WriteInteger("Interlock Info", "Door Enabled", machineSetupData.InterlockInfo.DoorInterlockEnabled);
		iniFile->WriteInteger("Interlock Info", "NC Interlock A Value", machineSetupData.InterlockInfo.NCInterlockAValue);

		iniFile->WriteBool("Buzzer Info", "Buzzer Continuous On", (machineSetupData.BuzzerInfo.BuzzerContinuousOn != 0));
		iniFile->WriteInteger("Buzzer Info", "Buzzer On Time", machineSetupData.BuzzerInfo.BuzzerOnTime);
		
		for (int stepMotorIndex = 0; stepMotorIndex < MAX_STEP_MOTOR_COUNT; stepMotorIndex++)
		{
			iniFile->WriteFloat("NC Info", "NC Zero Pos " + IntToStr(stepMotorIndex + 1), machineSetupData.ZeroPositionValue[stepMotorIndex]);
		}

		iniFile->WriteInteger("LED Control Info", "Eye Protection Mode Enabled", machineSetupData.LEDControlInfo.EyeProtectionModeEnabled);
		iniFile->WriteInteger("LED Control Info", "Eye Protection LED On Time", machineSetupData.LEDControlInfo.LEDOnTime);
		iniFile->WriteInteger("LED Control Info", "Eye Protection LED Off Delay", machineSetupData.LEDControlInfo.LEDOffDelay);

		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Base Speed", machineSetupData.ServoMotorData[motorIndex].BaseSpeed);
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Acc Time", machineSetupData.ServoMotorData[motorIndex].AccTime);
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Dec Time", machineSetupData.ServoMotorData[motorIndex].DecTime);
			iniFile->WriteBool("Servo " + IntToStr(motorIndex), "Direction", machineSetupData.ServoMotorData[motorIndex].Dir);
		}

		iniFile->WriteInteger("Alarm Level", "Pressure Alarm Level", machineSetupData.AlarmSetupInfo.PressureAlarmLevel);
		iniFile->WriteInteger("Alarm Level", "Vacuum Alarm Level 1", machineSetupData.AlarmSetupInfo.VacuumAlarmLevel1);
		iniFile->WriteInteger("Alarm Level", "Vacuum Alarm Level 2", machineSetupData.AlarmSetupInfo.VacuumAlarmLevel2);
		iniFile->WriteInteger("Alarm Level", "Temperature Alarm Level 1", machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel1);
		iniFile->WriteInteger("Alarm Level", "Temperature Alarm Level 2", machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel2);
		iniFile->WriteInteger("Alarm Level", "Temperature Alarm Level 3", machineSetupData.AlarmSetupInfo.TemperatureAlarmLevel3);

    	delete iniFile;
    }
}
//---------------------------------------------------------------------------
bool __fastcall ReadCameraMapData(AnsiString fileName, TCameraMapInfo *cameraMapInfo)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
		{
			cameraMapInfo[globalCamIndex].SPBIndex = iniFile->ReadInteger("Camera Map " + IntToStr(globalCamIndex + 1), "SPB Index", 0);
			cameraMapInfo[globalCamIndex].CamIndex = iniFile->ReadInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Cam Index", 0);
			cameraMapInfo[globalCamIndex].CameraInspectPosition = iniFile->ReadInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Inspect Position", 0);
		}
		delete iniFile;
	}
	else
	{
		for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
		{
			cameraMapInfo[globalCamIndex].SPBIndex = 0;
			cameraMapInfo[globalCamIndex].CamIndex = 0;
			cameraMapInfo[globalCamIndex].CameraInspectPosition = 0;
		}
		returnValue = false;
    }
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall WriteCameraMapData(AnsiString fileName, TCameraMapInfo *cameraMapInfo)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
    if (iniFile)
    {
		for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
		{
			iniFile->WriteInteger("Camera Map " + IntToStr(globalCamIndex + 1), "SPB Index", cameraMapInfo[globalCamIndex].SPBIndex);
			iniFile->WriteInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Cam Index", cameraMapInfo[globalCamIndex].CamIndex);
			iniFile->WriteInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Inspect Position", cameraMapInfo[globalCamIndex].CameraInspectPosition);
		}
    	delete iniFile;
	}
    else
    {
    	returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall ReadSPBSystemSetupData(AnsiString fileName, TSPBSystemSetupData *spbSystemSetupData,
	TCameraMapInfo *cameraMapInfo)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int spbIndex = 0; spbIndex < SYSTEM_SPB_MAX_COUNT; spbIndex++)
		{
			memset(&spbSystemSetupData[spbIndex], 0, sizeof(TSPBSystemSetupData));
			memcpy(spbSystemSetupData[spbIndex].CameraMapInfo, cameraMapInfo, SYSTEM_TOTAL_CAMERA_COUNT * sizeof(TCameraMapInfo));
			
			spbSystemSetupData[spbIndex].DefaultCPBProgramID = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
				"Default CPB Program ID", PID_CPB | ('0' << 8) | '0');

        	for (int cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
			{
				spbSystemSetupData[spbIndex].CPBEnabled[cpbIndex] = (iniFile->ReadBool("SPB " + IntToStr(spbIndex + 1),
					"CPB Enable " + IntToStr(cpbIndex + 1), false) ? 1 : 0);
				spbSystemSetupData[spbIndex].CPBSDRSizeType[cpbIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB SDR Size Type " + IntToStr(cpbIndex + 1), 0);
				spbSystemSetupData[spbIndex].CPBClockKind[cpbIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB Clock Kind " + IntToStr(cpbIndex + 1), 0);
				spbSystemSetupData[spbIndex].CameraDistributionIndex[cpbIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"Camera Distribution " + IntToStr(cpbIndex + 1), 0);
			}
			for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
			{
				spbSystemSetupData[spbIndex].CameraHardwarePosition[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"Camera Hardware Position " + IntToStr(camIndex + 1), 0);
//		        SPBInfo[spbIndex].ShutterSpeed[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
//                	"Shutter Speed " + IntToStr(camIndex + 1), 100);
				spbSystemSetupData[spbIndex].GlobalCameraIndex[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"Global Camera Index " + IntToStr(camIndex + 1), 0);

				spbSystemSetupData[spbIndex].InspectPosition[camIndex] =
					cameraMapInfo[spbSystemSetupData[spbIndex].GlobalCameraIndex[camIndex]].CameraInspectPosition;
				if (spbSystemSetupData[spbIndex].InspectPosition[camIndex] != CAMERA_POSITION_3D)
				{
					spbSystemSetupData[spbIndex].CameraKind[camIndex] = CAMERA_KIND_CIS;
				}
				else		// 3D camera
				{
					spbSystemSetupData[spbIndex].CameraKind[camIndex] = CAMERA_KIND_RANGER_3D;
				}
			}
			spbSystemSetupData[spbIndex].CamMask = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
				"Camera Mask", 0);

			spbSystemSetupData[spbIndex].ImageTransferMethod = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1), "Image Transfer Method", SPB_IMAGE_TRANSFER_METHOD_CHECKSUM);
		}
    	delete iniFile;
    }
    else
	{
		for (int spbIndex = 0; spbIndex < SYSTEM_SPB_MAX_COUNT; spbIndex++)
		{
			memset(&spbSystemSetupData[spbIndex], 0, sizeof(TSPBSystemSetupData));
			memcpy(spbSystemSetupData[spbIndex].CameraMapInfo, cameraMapInfo, SYSTEM_TOTAL_CAMERA_COUNT * sizeof(TCameraMapInfo));
			
			spbSystemSetupData[spbIndex].DefaultCPBProgramID = (PID_CPB | ('0' << 8) | '0');

			for (int cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
			{
				spbSystemSetupData[spbIndex].CPBEnabled[cpbIndex] = 0;
				spbSystemSetupData[spbIndex].CPBSDRSizeType[cpbIndex] = 0;
				spbSystemSetupData[spbIndex].CPBClockKind[cpbIndex] = 0;
				spbSystemSetupData[spbIndex].CameraDistributionIndex[cpbIndex] = 0;
			}
			for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
			{
				spbSystemSetupData[spbIndex].CameraHardwarePosition[camIndex] = 0;
//		        SPBInfo[spbIndex].ShutterSpeed[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
//                	"Shutter Speed " + IntToStr(camIndex + 1), 100);
				spbSystemSetupData[spbIndex].GlobalCameraIndex[camIndex] = 0;
				spbSystemSetupData[spbIndex].InspectPosition[camIndex] = 0;
				spbSystemSetupData[spbIndex].CameraKind[camIndex] = CAMERA_KIND_CIS;
			}
			spbSystemSetupData[spbIndex].CamMask = 0;
			spbSystemSetupData[spbIndex].ImageTransferMethod = SPB_IMAGE_TRANSFER_METHOD_CHECKSUM;
		}
		returnValue = false;
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall WriteSPBSystemSetupData(AnsiString fileName, TSPBSystemSetupData *spbSystemSetupData)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
    if (iniFile)
    {
        for (int spbIndex = 0; spbIndex < SYSTEM_SPB_MAX_COUNT; spbIndex++)
        {
        	iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
        		"Default CPB Program ID", spbSystemSetupData[spbIndex].DefaultCPBProgramID);

        	for (int cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
            {
            	iniFile->WriteBool("SPB " + IntToStr(spbIndex + 1),
					"CPB Enable " + IntToStr(cpbIndex + 1), spbSystemSetupData[spbIndex].CPBEnabled[cpbIndex]);
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB SDR Size Type " + IntToStr(cpbIndex + 1), spbSystemSetupData[spbIndex].CPBSDRSizeType[cpbIndex]);
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB Clock Kind " + IntToStr(cpbIndex + 1), spbSystemSetupData[spbIndex].CPBClockKind[cpbIndex]);
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"Camera Distribution " + IntToStr(cpbIndex + 1), spbSystemSetupData[spbIndex].CameraDistributionIndex[cpbIndex]);
			}
			for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
			{
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"Camera Hardware Position " + IntToStr(camIndex + 1), spbSystemSetupData[spbIndex].CameraHardwarePosition[camIndex]);
//		        iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
//					"Shutter Speed " + IntToStr(camIndex + 1), SPBInfo[spbIndex].ShutterSpeed[camIndex]);
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
                	"Global Camera Index " + IntToStr(camIndex + 1), spbSystemSetupData[spbIndex].GlobalCameraIndex[camIndex]);
			}
			iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
				"Camera Mask", spbSystemSetupData[spbIndex].CamMask);

			iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1), "Image Transfer Method", spbSystemSetupData[spbIndex].ImageTransferMethod);
		}
		delete iniFile;
	}
    else
    {
    	returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall ReadProductData(AnsiString fileName, TProductData &productData,
	TMachineParams &machineParams, TMachineSetupData &machineSetupData)
{
    if (!FileExists(fileName))
    {
		return false;
    }
    else
    {
		TIniFile *iniFile = new TIniFile(fileName);
		if (iniFile)
		{
			int majorVersion = iniFile->ReadInteger("Product Data Verion", "Major Version", 0);
			int minorVersion = iniFile->ReadInteger("Product Data Verion", "Minor Version", 0);
			// compare with current version
			if (majorVersion != CURRENT_PRODUCT_DATA_MAJOR_VERSION || minorVersion != CURRENT_PRODUCT_DATA_MINOR_VERSION)
			{
				return false;
			}

			productData.ProductCode = iniFile->ReadString("Product Info", "Product Code", "");
			productData.ProductName = iniFile->ReadString("Product Info", "Product Name", "");
			productData.TabletType = iniFile->ReadInteger("Tablet Info", "Tablet Type", 0);
			productData.TabletShape = iniFile->ReadInteger("Tablet Info", "Tablet Shape", 0);
			productData.TabletLength = iniFile->ReadFloat("Tablet Info", "Tablet Length", 0);
			productData.TabletWidth = iniFile->ReadFloat("Tablet Info", "Tablet Width", 0);
			productData.TabletThick = iniFile->ReadFloat("Tablet Info", "Tablet Thick", 0);
			productData.TabletSideThick = iniFile->ReadFloat("Tablet Info", "Tablet Side Thick", 0);
			productData.EngraveType = iniFile->ReadInteger("Engrave Info", "Engrave Type", 0);
			productData.EngravePos = iniFile->ReadInteger("Engrave Info", "Engrave Pos", 0);
			productData.PlateTablet = iniFile->ReadBool("Tablet Info", "Plate Tablet", false);
			productData.Arrange = iniFile->ReadBool("Tablet Info", "Arrange", true);
			productData.SymmetricLineCount = iniFile->ReadInteger("Tablet Info", "Symmetric Line Count", 1);
			productData.StudiedSensor1Length = iniFile->ReadInteger("Machine Parameter", "Studied Sensor 1 Length", 1000);
			productData.StudiedSensor2Length = iniFile->ReadInteger("Machine Parameter", "Studied Sensor 2 Length", 1000);
			productData.StudiedSensorIntervalA = iniFile->ReadInteger("Machine Parameter", "Studied Sensor Interval A", machineSetupData.SensorIntervalA);
			productData.StudiedSensorIntervalB = iniFile->ReadInteger("Machine Parameter", "Studied Sensor Interval B", machineSetupData.SensorIntervalB);

			productData.LastInspectionTime.Val = iniFile->ReadFloat("Tablet Info", "Last Inspection Time", 0);
			productData.TabletLayerCount = iniFile->ReadInteger("Tablet Info", "Tablet Layer Count", 1);

			for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	        {
				productData.BoundaryLeft[globalCameraIndex] = iniFile->ReadInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Left", 0);
	            productData.BoundaryTop[globalCameraIndex] = iniFile->ReadInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Top", 0);
	            productData.BoundaryRight[globalCameraIndex] = iniFile->ReadInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Right", SYSTEM_CAMERA_WIDTH);
	            productData.BoundaryBottom[globalCameraIndex] = iniFile->ReadInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Bottom", SYSTEM_CAMERA_HEIGHT);
				productData.ShutterSpeed[globalCameraIndex] = iniFile->ReadInteger("Shutter Speed", IntToStr(globalCameraIndex + 1), 10);
				productData.ThresholdFor3D[globalCameraIndex] = iniFile->ReadInteger("Threshold For 3D", IntToStr(globalCameraIndex + 1), 10);
	        }

			productData.ProcessingStep = iniFile->ReadInteger("Processing Info", "Processing Step", TABLET_PROCESSING_STEP_CALIBRATION_REQUIRED);
            productData.TabletColorCode = iniFile->ReadString("Tablet Info", "Tablet Color Code", "");
            productData.PrintColorCode = iniFile->ReadString("Tablet Info", "Print Color Code", "");

			// read motor params
			int msTabletTypeIndex = 0, msTabletShapeIndex = 0;

			msTabletTypeIndex = GetMSTabletTypeIndex(productData.TabletType);
			msTabletShapeIndex = GetMSTabletShapeIndex(productData.TabletShape);

			for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
            {
				for (int speedIndex = 0; speedIndex < MOTOR_SPEED_STEP_COUNT_FOR_PRODUCT; speedIndex++)
				{
					productData.MotorSpeedList[motorIndex][speedIndex] = iniFile->ReadInteger("Motor " + IntToStr(motorIndex + 1) + " Speed", IntToStr(speedIndex + 1),
						machineParams.MotorSpeedList[msTabletTypeIndex][msTabletShapeIndex][motorIndex][speedIndex]);
                }
			}

			for (int layerIndex = 0; layerIndex < MAX_TABLET_LAYER_COUNT; layerIndex++)
			{
				productData.MultiLayeredTabletColor[layerIndex] = iniFile->ReadInteger("Tablet Color", IntToStr(layerIndex + 1), clWhite);
			}

			productData.ProductionCount = iniFile->ReadInteger("Production Info", "Production Count", 0);

			productData.MachineRunOption.MaxSpeedTrainingMode = iniFile->ReadInteger("Machine Parameter", "Max Speed Training Mode", MAX_SPEED_TRAINING_MODE_AUTO);
			productData.MachineRunOption.ManualMaxSpeed = iniFile->ReadInteger("Machine Parameter", "Manual Max Speed", 100);
//			productData.MachineRunOption.EmptySensorIndex = iniFile->ReadInteger("Machine Parameter", "Empty Sensor Index",  0);
    		productData.MachineRunOption.ManualModeSensorIndex = iniFile->ReadInteger("Machine Parameter", "Manual Mode Index", machineSetupData.VFInfo.ManualModeSensorIndex);
            productData.MachineRunOption.ManualModeSensorActiveRatio = iniFile->ReadInteger("Machine Parameter", "Manual Mode Sensor Active Ratio", machineSetupData.VFInfo.ManualModeSensorActiveRatio);

			productData.MachineRunOption.EmptySensorActiveRatio = iniFile->ReadInteger("Machine Parameter", "Empty Sensor Active Ratio", 50);
//			productData.MachineRunOption.FullSensorIndex = iniFile->ReadInteger("Machine Parameter", "Full Sensor Index", 1);
			productData.MachineRunOption.FullSensorActiveRatio = iniFile->ReadInteger("Machine Parameter", "Full Sensor Active Ratio", 50);
            productData.MachineRunOption.StartSpeed = iniFile->ReadInteger ("Machine Parameter", "Start Speed", 40);
			productData.MachineRunOption.SuctionDisk1InverterSpeed = iniFile->ReadInteger("Machine Parameter", "Suction Disk 1 Inverter Speed", 255);
			productData.MachineRunOption.SuctionDisk2InverterSpeed = iniFile->ReadInteger("Machine Parameter", "Suction Disk 2 Inverter Speed", 255);
			productData.MachineRunOption.AirKnifeSpeed = iniFile->ReadInteger("Machine Parameter", "Air Knife Speed", 2);

			productData.RotatingGuideKind = iniFile->ReadInteger("Change Part", "Rotating Guide Kind", GetDefaultGuideKind(0, productData.TabletWidth));
			productData.FixedGuideKind = iniFile->ReadInteger("Change Part", "Fixed Guide Kind", GetDefaultGuideKind(1, productData.TabletWidth));
			productData.VerticalGate2Kind = iniFile->ReadInteger("Change Part", "Vertical Gate 2 Kind", GetDefaultVGateKind(1, productData.TabletWidth));
			GetDefaultNCPosition(productData, productData.NCMotorPos, machineSetupData.InterlockInfo.NCInterlockAValue / 100.0 -
				machineSetupData.ZeroPositionValue[3] + machineSetupData.ZeroPositionValue[0]);
			productData.NCMotorPos[0] = iniFile->ReadFloat("NC Encoder Position", "Motor 1 Pos", productData.NCMotorPos[0]);
			productData.NCMotorPos[1] = iniFile->ReadFloat("NC Encoder Position", "Motor 2 Pos", productData.NCMotorPos[1]);
			productData.NCMotorPos[2] = iniFile->ReadFloat("NC Encoder Position", "Motor 3 Pos", productData.NCMotorPos[2]);
			productData.NCMotorPos[3] = iniFile->ReadFloat("NC Encoder Position", "Motor 4 Pos", productData.NCMotorPos[3]);
			productData.NCMotorPos[4] = iniFile->ReadFloat("NC Encoder Position", "Motor 5 Pos", productData.NCMotorPos[4]);

			productData.PartialCaptureMode = iniFile->ReadInteger("Capture Info", "Partial Capture Mode", 0);
			productData.LampKind = iniFile->ReadInteger("Tablet Info", "Lamp Kind", MACHINE_LAMP_KIND_NORMAL_TABLET);
			delete iniFile;
		}
		else
		{
			return false;
        }
	}
    return true;
}
//---------------------------------------------------------------------------
bool __fastcall WriteProductData(AnsiString fileName, TProductData &productData)
{
	TIniFile *iniFile = new TIniFile(fileName);

    if (iniFile)
    {
	// check revision
	    iniFile->WriteInteger("Product Data Verion", "Major Version", CURRENT_PRODUCT_DATA_MAJOR_VERSION);
		iniFile->WriteInteger("Product Data Verion", "Minor Version", CURRENT_PRODUCT_DATA_MINOR_VERSION);

		iniFile->WriteString("Product Info", "Product Code", productData.ProductCode);
        iniFile->WriteString("Product Info", "Product Name", productData.ProductName);
        iniFile->WriteInteger("Tablet Info", "Tablet Type", productData.TabletType);
        iniFile->WriteInteger("Tablet Info", "Tablet Shape", productData.TabletShape);
        iniFile->WriteFloat("Tablet Info", "Tablet Length", productData.TabletLength);
        iniFile->WriteFloat("Tablet Info", "Tablet Width", productData.TabletWidth);
        iniFile->WriteFloat("Tablet Info", "Tablet Thick", productData.TabletThick);
        iniFile->WriteFloat("Tablet Info", "Tablet Side Thick", productData.TabletSideThick);
        iniFile->WriteInteger("Engrave Info", "Engrave Type", productData.EngraveType);
        iniFile->WriteInteger("Engrave Info", "Engrave Pos", productData.EngravePos);
		iniFile->WriteBool("Tablet Info", "Plate Tablet", productData.PlateTablet);
		iniFile->WriteBool("Tablet Info", "Arrange", productData.Arrange);
		iniFile->WriteInteger("Tablet Info", "Symmetric Line Count", productData.SymmetricLineCount);

        iniFile->WriteInteger("Processing Info", "Processing Step", productData.ProcessingStep);
        iniFile->WriteString("Tablet Info", "Tablet Color Code", productData.TabletColorCode);
        iniFile->WriteString("Tablet Info", "Print Color Code", productData.PrintColorCode);

//		iniFile->WriteInteger("Tablet Info", "Tablet Size", productData.TabletSize);
		iniFile->WriteFloat("Tablet Info", "Last Inspection Time", productData.LastInspectionTime.Val);

		iniFile->WriteInteger("Tablet Info", "Tablet Layer Count", productData.TabletLayerCount);



		for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
        {
			iniFile->WriteInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Left", productData.BoundaryLeft[globalCameraIndex]);
            iniFile->WriteInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Top", productData.BoundaryTop[globalCameraIndex]);
			iniFile->WriteInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Right", productData.BoundaryRight[globalCameraIndex]);
			iniFile->WriteInteger("Boundary of Camera " + IntToStr(globalCameraIndex + 1), "Bottom", productData.BoundaryBottom[globalCameraIndex]);
			iniFile->WriteInteger("Shutter Speed", IntToStr(globalCameraIndex + 1), productData.ShutterSpeed[globalCameraIndex]);
			iniFile->WriteInteger("Threshold For 3D", IntToStr(globalCameraIndex + 1), productData.ThresholdFor3D[globalCameraIndex]);
		}


		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			for (int speedIndex = 0; speedIndex < MOTOR_SPEED_STEP_COUNT_FOR_PRODUCT; speedIndex++)
			{
				iniFile->WriteInteger("Motor " + IntToStr(motorIndex + 1) + " Speed", IntToStr(speedIndex + 1), productData.MotorSpeedList[motorIndex][speedIndex]);
			}
		}

		for (int layerIndex = 0; layerIndex < MAX_TABLET_LAYER_COUNT; layerIndex++)
		{
			iniFile->WriteInteger("Tablet Color", IntToStr(layerIndex + 1), productData.MultiLayeredTabletColor[layerIndex]);
		}

		iniFile->WriteInteger("Production Info", "Production Count", productData.ProductionCount);

		iniFile->WriteInteger("Machine Parameter", "Max Speed Training Mode", productData.MachineRunOption.MaxSpeedTrainingMode);
		iniFile->WriteInteger("Machine Parameter", "Manual Max Speed", productData.MachineRunOption.ManualMaxSpeed);
   		iniFile->WriteInteger("Machine Parameter", "Manual Mode Index", productData.MachineRunOption.ManualModeSensorIndex);
        iniFile->WriteInteger("Machine Parameter", "Manual Mode Sensor Active Ratio", productData.MachineRunOption.ManualModeSensorActiveRatio);

//		iniFile->WriteInteger("Machine Parameter", "Empty Sensor Index", productData.MachineRunOption.EmptySensorIndex);
		iniFile->WriteInteger("Machine Parameter", "Empty Sensor Active Ratio", productData.MachineRunOption.EmptySensorActiveRatio);
//		iniFile->WriteInteger("Machine Parameter", "Full Sensor Index", productData.MachineRunOption.FullSensorIndex);
		iniFile->WriteInteger("Machine Parameter", "Full Sensor Active Ratio", productData.MachineRunOption.FullSensorActiveRatio);
        iniFile->WriteInteger("Machine Parameter", "Start Speed", productData.MachineRunOption.StartSpeed);
		iniFile->WriteInteger("Machine Parameter", "Suction Disk 1 Inverter Speed", productData.MachineRunOption.SuctionDisk1InverterSpeed);
		iniFile->WriteInteger("Machine Parameter", "Suction Disk 2 Inverter Speed", productData.MachineRunOption.SuctionDisk2InverterSpeed);
		iniFile->WriteInteger("Machine Parameter", "Air Knife Speed", productData.MachineRunOption.AirKnifeSpeed);		

		iniFile->WriteInteger("Machine Parameter", "Studied Sensor 1 Length", productData.StudiedSensor1Length);
		iniFile->WriteInteger("Machine Parameter", "Studied Sensor 2 Length", productData.StudiedSensor2Length);
		iniFile->WriteInteger("Machine Parameter", "Studied Sensor Interval A", productData.StudiedSensorIntervalA);
		iniFile->WriteInteger("Machine Parameter", "Studied Sensor Interval B", productData.StudiedSensorIntervalB);

		iniFile->WriteInteger("Change Part", "Rotating Guide Kind", productData.RotatingGuideKind);
		iniFile->WriteInteger("Change Part", "Fixed Guide Kind", productData.FixedGuideKind);
		iniFile->WriteInteger("Change Part", "Vertical Gate 2 Kind", productData.VerticalGate2Kind);
		iniFile->WriteFloat("NC Encoder Position", "Motor 1 Pos", productData.NCMotorPos[0]);
		iniFile->WriteFloat("NC Encoder Position", "Motor 2 Pos", productData.NCMotorPos[1]);
		iniFile->WriteFloat("NC Encoder Position", "Motor 3 Pos", productData.NCMotorPos[2]);
		iniFile->WriteFloat("NC Encoder Position", "Motor 4 Pos", productData.NCMotorPos[3]);
		iniFile->WriteFloat("NC Encoder Position", "Motor 5 Pos", productData.NCMotorPos[4]);

		iniFile->WriteInteger("Capture Info", "Partial Capture Mode", productData.PartialCaptureMode);
		iniFile->WriteInteger("Tablet Info", "Lamp Kind", productData.LampKind);

        delete iniFile;
        return true;
    }
    else
	{
    	return false;
    }
}
//---------------------------------------------------------------------------
/*
__fastcall TSystemInfor::TSystemInfor()
{
	SpeedIndex = 0;
}
//---------------------------------------------------------------------------
bool __fastcall TSystemInfor::LoadData(AnsiString fileName)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
    if (iniFile)
    {
        for (int spbIndex = 0; spbIndex < SYSTEM_SPB_MAX_COUNT; spbIndex++)
        {
        	SPBInfo[spbIndex].DefaultCPBProgramID = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
        		"Default CPB Program ID", PID_CPB | ('0' << 8) | '0');

        	for (int cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
            {
                SPBInfo[spbIndex].CPBEnabled[cpbIndex] = iniFile->ReadBool("SPB " + IntToStr(spbIndex + 1),
                	"CPB Enable " + IntToStr(cpbIndex + 1), false);
                SPBInfo[spbIndex].CPBSDRSizeType[cpbIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB SDR Size Type " + IntToStr(cpbIndex + 1), 0);
				SPBInfo[spbIndex].CPBClockKind[cpbIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB Clock Kind " + IntToStr(cpbIndex + 1), 0);
				SPBInfo[spbIndex].CameraDistribution[cpbIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
                	"Camera Distribution " + IntToStr(cpbIndex + 1), 0);
            }
	        for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	        {
		        SPBInfo[spbIndex].CameraHardwarePosition[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
                	"Camera Hardware Position " + IntToStr(camIndex + 1), 0);
		        SPBInfo[spbIndex].ShutterSpeed[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
					"Shutter Speed " + IntToStr(camIndex + 1), 100);
		        SPBInfo[spbIndex].GlobalCameraIndex[camIndex] = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
                	"Global Camera Index " + IntToStr(camIndex + 1), 0);
	        }
            SPBInfo[spbIndex].CamMask = iniFile->ReadInteger("SPB " + IntToStr(spbIndex + 1),
            	"Camera Mask", 0);
        }

        for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
        {
			CameraMapInfo[globalCamIndex].SPBIndex = iniFile->ReadInteger("Camera Map " + IntToStr(globalCamIndex + 1), "SPB Index", 0);
            CameraMapInfo[globalCamIndex].CamIndex = iniFile->ReadInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Cam Index", 0);
            CameraMapInfo[globalCamIndex].CameraInspectPosition = iniFile->ReadInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Inspect Position", 0);

//            ShutterSpeed[globalCamIndex] = iniFile->ReadInteger("Calibration", "Shutter Speed " + IntToStr(globalCamIndex + 1), 100);
//            Resolution[globalCamIndex] = iniFile->ReadFloat("Calibration", "Resolution " + IntToStr(globalCamIndex + 1), 0);
//            LEDOnMask[globalCamIndex] = iniFile->ReadInteger("Calibration", "LED On Mask " + IntToStr(globalCamIndex + 1), 0);
        }

    	delete iniFile;
    }
    else
    {
        for (int spbIndex = 0; spbIndex < SYSTEM_SPB_MAX_COUNT; spbIndex++)
        {
        	SPBInfo[spbIndex].DefaultCPBProgramID = PID_CPB | ('0' << 8) | '0';

        	for (int cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
            {
            	SPBInfo[spbIndex].CPBEnabled[cpbIndex] = false;
            }
	        for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	        {
		        SPBInfo[spbIndex].CameraHardwarePosition[camIndex] = 0;
            }
        }

        for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
		{
			CameraMapInfo[globalCamIndex].SPBIndex = 0;
			CameraMapInfo[globalCamIndex].CamIndex = 0;
//			ShutterSpeed[globalCamIndex] = 100;
//			LEDOnMask[globalCamIndex] = 0;
		}
		returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall TSystemInfor::SaveData(AnsiString fileName)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
    if (iniFile)
    {
        for (int spbIndex = 0; spbIndex < SYSTEM_SPB_MAX_COUNT; spbIndex++)
        {
        	iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
        		"Default CPB Program ID", SPBInfo[spbIndex].DefaultCPBProgramID);

        	for (int cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
            {
            	iniFile->WriteBool("SPB " + IntToStr(spbIndex + 1),
                	"CPB Enable " + IntToStr(cpbIndex + 1), SPBInfo[spbIndex].CPBEnabled[cpbIndex]);
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB SDR Size Type " + IntToStr(cpbIndex + 1), SPBInfo[spbIndex].CPBSDRSizeType[cpbIndex]);
				iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"CPB Clock Kind " + IntToStr(cpbIndex + 1), SPBInfo[spbIndex].CPBClockKind[cpbIndex]);
                iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
                	"Camera Distribution " + IntToStr(cpbIndex + 1), SPBInfo[spbIndex].CameraDistribution[cpbIndex]);
            }
	        for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	        {
            	iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
                	"Camera Hardware Position " + IntToStr(camIndex + 1), SPBInfo[spbIndex].CameraHardwarePosition[camIndex]);
		        iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
					"Shutter Speed " + IntToStr(camIndex + 1), SPBInfo[spbIndex].ShutterSpeed[camIndex]);
		        iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
                	"Global Camera Index " + IntToStr(camIndex + 1), SPBInfo[spbIndex].GlobalCameraIndex[camIndex]);
	        }
            iniFile->WriteInteger("SPB " + IntToStr(spbIndex + 1),
            	"Camera Mask", SPBInfo[spbIndex].CamMask);
        }

        for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
        {
        	iniFile->WriteInteger("Camera Map " + IntToStr(globalCamIndex + 1), "SPB Index", CameraMapInfo[globalCamIndex].SPBIndex);
            iniFile->WriteInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Cam Index", CameraMapInfo[globalCamIndex].CamIndex);
			iniFile->WriteInteger("Camera Map " + IntToStr(globalCamIndex + 1), "Inspect Position", CameraMapInfo[globalCamIndex].CameraInspectPosition);

//            iniFile->WriteInteger("Calibration", "Shutter Speed " + IntToStr(globalCamIndex + 1), ShutterSpeed[globalCamIndex]);
//			iniFile->WriteFloat("Calibration", "Resolution " + IntToStr(globalCamIndex + 1), Resolution[globalCamIndex]);
//            iniFile->WriteInteger("Calibration", "LED On Mask " + IntToStr(globalCamIndex + 1), LEDOnMask[globalCamIndex]);
        }
    	delete iniFile;
	}
    else
    {
    	returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
*/
bool __fastcall SetProgramPath(TProgramPath &path)
{
    TRegIniFile *regIniFile = new TRegIniFile("Application");
	bool returnValue = true;
    if (regIniFile)
    {
	    regIniFile->RootKey = HKEY_LOCAL_MACHINE;
	    regIniFile->OpenKey(PROGRAM_REGISTRY_KEY, true);

	    path.Root = regIniFile->ReadString("Folder", "Root_Tablet", "");

		if (!DirectoryExists(path.Root))
	    {
        	returnValue = false;
        }
        else
        {
        	path.Env = path.Root + "\\Env";
            path.Hex = path.Root + "\\Hex";
            path.Image = path.Root + "\\Image";
            path.Product = path.Root + "\\Product";
            path.Log = path.Root + "\\Log";
			path.Defect = path.Root + "\\Defect";
		}
		delete regIniFile;
	}
	char tempPath[256];
	GetTempPathA(256, tempPath);
	path.Temp = AnsiString(tempPath) + "\\tvm_pc_dir";
	if (!DirectoryExists(path.Temp))
	{
		ForceDirectories(path.Temp);
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall ReadMachineParams(AnsiString fileName, TMachineParams &machineParams)		// pc saved params
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
    {
		for (int tabletType = 0; tabletType < MS_TABLET_TYPE_COUNT; tabletType++)
	    {
			for (int tabletShape = 0; tabletShape < MS_TABLET_SHAPE_COUNT; tabletShape++)
	        {
				for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		        {
					for (int speedIndex = 0; speedIndex < MS_MOTOR_SPEED_STEP_COUNT; speedIndex++)
				    {
						machineParams.MotorSpeedList[tabletType][tabletShape][motorIndex][speedIndex] =
							iniFile->ReadInteger("Step " + IntToStr(tabletType * 100 + tabletShape * 10 + motorIndex), "Speed Modifier " + IntToStr(speedIndex), 500000);
		            }
		        }
	        }
		}
		for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
        {
			machineParams.DiscCenterPos[globalCameraIndex] =
				iniFile->ReadInteger("Disc Center Pos", IntToStr(globalCameraIndex + 1), 0);
			machineParams.CameraResolution[globalCameraIndex] =
				iniFile->ReadFloat("Camera Resolution", IntToStr(globalCameraIndex + 1), 30);
		}

		for (int camTestIndex = 0; camTestIndex < 4; camTestIndex++)
		{
			machineParams.CameraBrightnessEvalValue[camTestIndex] =
				iniFile->ReadInteger("Camera Brightness Eval Value", IntToStr(camTestIndex + 1), 100);
		}
    }
    else
    {
		for (int tabletType = 0; tabletType < MS_TABLET_TYPE_COUNT; tabletType++)
	    {
			for (int tabletShape = 0; tabletShape < MS_TABLET_SHAPE_COUNT; tabletShape++)
			{
		    	for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		        {
					for (int speedIndex = 0; speedIndex < MS_MOTOR_SPEED_STEP_COUNT; speedIndex++)
				    {
						machineParams.MotorSpeedList[tabletType][tabletShape][motorIndex][speedIndex] = 500000;
		            }
		        }
	        }
	    }
		for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
        {
			machineParams.DiscCenterPos[globalCameraIndex] = 0;
			machineParams.CameraResolution[globalCameraIndex] = 30;
		}
		for (int camTestIndex = 0; camTestIndex < 4; camTestIndex++)
		{
			machineParams.CameraBrightnessEvalValue[camTestIndex] = 100;
		}
        returnValue = false;
	}


	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall WriteMachineParams(AnsiString fileName, TMachineParams &machineParams)		// pc saved params
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
    {
		for (int tabletType = 0; tabletType < MS_TABLET_TYPE_COUNT; tabletType++)
	    {
			for (int tabletShape = 0; tabletShape < MS_TABLET_SHAPE_COUNT; tabletShape++)
			{
		    	for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		        {
					for (int speedIndex = 0; speedIndex < MS_MOTOR_SPEED_STEP_COUNT; speedIndex++)
					{
                    	iniFile->WriteInteger("Step " + IntToStr(tabletType * 100 + tabletShape * 10 + motorIndex), "Speed Modifier " + IntToStr(speedIndex),
							machineParams.MotorSpeedList[tabletType][tabletShape][motorIndex][speedIndex]);
		            }
		        }
			}
	    }

		for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
        {
        	iniFile->WriteInteger("Disc Center Pos", IntToStr(globalCameraIndex + 1), machineParams.DiscCenterPos[globalCameraIndex]);
			iniFile->WriteInteger("Camera Resolution", IntToStr(globalCameraIndex + 1), machineParams.CameraResolution[globalCameraIndex]);
		}

		for (int camTestIndex = 0; camTestIndex < 4; camTestIndex++)
		{
			iniFile->WriteInteger("Camera Brightness Eval Value", IntToStr(camTestIndex + 1), machineParams.CameraBrightnessEvalValue[camTestIndex]);
		}
    }
    else
    {
        returnValue = false;
    }
	return returnValue;
}
//---------------------------------------------------------------------------
/*
bool __fastcall ReadServoMotorInfo(AnsiString fileName, TServoMotorInfo *servoMotorInfo)
{
	if (!FileExists(fileName)) return false;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			servoMotorInfo[motorIndex].BaseSpeed = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Base Speed", 100);
			servoMotorInfo[motorIndex].AccTime = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Acc Time", 1000);
			servoMotorInfo[motorIndex].DecTime = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Dec Time", 1000);
			servoMotorInfo[motorIndex].IsPositiveDirection = iniFile->ReadBool("Servo " + IntToStr(motorIndex), "Positive Direction", true);
		}
		delete iniFile;
		return true;
	}
	else
	{
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			servoMotorInfo[motorIndex].BaseSpeed = 100;
			servoMotorInfo[motorIndex].AccTime = 1000;
			servoMotorInfo[motorIndex].DecTime = 1000;
			servoMotorInfo[motorIndex].IsPositiveDirection = true;
		}
		return false;
	}
}
//---------------------------------------------------------------------------
void __fastcall WriteServoMotorInfo(AnsiString fileName, TServoMotorInfo *servoMotorInfo)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Base Speed", servoMotorInfo[motorIndex].BaseSpeed);
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Acc Time", servoMotorInfo[motorIndex].AccTime);
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Dec Time", servoMotorInfo[motorIndex].DecTime);
			iniFile->WriteBool("Servo " + IntToStr(motorIndex), "Positive Direction", servoMotorInfo[motorIndex].IsPositiveDirection);
		}

		delete iniFile;
	}
}
*/
//---------------------------------------------------------------------------
bool __fastcall ReadMachineOperationInfo(AnsiString fileName, TMachineOperationInfo &machineOperationInfo, TMachineSetupData &machineSetupData)		// read recent operation info
{
	if (!FileExists(fileName))
	{
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			machineOperationInfo.ServoMotorSpeed[motorIndex] = machineSetupData.ServoMotorData[motorIndex].BaseSpeed * 2;
		}
		return false;
	}
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		machineOperationInfo.Disk1InverterSpeed = iniFile->ReadInteger("Inverter Speed", "Suction Disk 1 Inverter Speed", 255);
		machineOperationInfo.Disk2InverterSpeed = iniFile->ReadInteger("Inverter Speed", "Suction Disk 2 Inverter Speed", 255);
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			machineOperationInfo.ServoMotorSpeed[motorIndex] = iniFile->ReadInteger("Servo " + IntToStr(motorIndex), "Target Speed", machineSetupData.ServoMotorData[motorIndex].BaseSpeed * 2);
		}

		machineOperationInfo.SpeedIndex = iniFile->ReadInteger("Control Option", "Speed Index", 0);
		delete iniFile;
		return true;
	}
	else
	{
		machineOperationInfo.Disk1InverterSpeed = 255;
		machineOperationInfo.Disk2InverterSpeed = 255;
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			machineOperationInfo.ServoMotorSpeed[motorIndex] = machineSetupData.ServoMotorData[motorIndex].BaseSpeed * 2;
		}
		machineOperationInfo.SpeedIndex = 0;
		return false;
	}
}
//---------------------------------------------------------------------------
void __fastcall WriteMachineOperationInfo(AnsiString fileName, TMachineOperationInfo &machineOperationInfo)		// write recent operation info
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteInteger("Inverter Speed", "Suction Disk 1 Inverter Speed", machineOperationInfo.Disk1InverterSpeed);
		iniFile->WriteInteger("Inverter Speed", "Suction Disk 2 Inverter Speed", machineOperationInfo.Disk2InverterSpeed);
		for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
		{
			iniFile->WriteInteger("Servo " + IntToStr(motorIndex), "Target Speed", machineOperationInfo.ServoMotorSpeed[motorIndex]);
		}
		iniFile->WriteInteger("Control Option", "Speed Index", machineOperationInfo.SpeedIndex);
		delete iniFile;
	}
}
//---------------------------------------------------------------------------
bool __fastcall SaveGradeData(AnsiString gradeFileName, TTabletGradeData &GradeData)
{
	TFileStream *fileStream = new TFileStream(gradeFileName, fmCreate);
    if (fileStream)
    {
		fileStream->Write(&GradeData, sizeof(TTabletGradeData));
    	delete fileStream;
        return true;
    }
    else
    {
    	return false;
    }
}
//---------------------------------------------------------------------------
bool __fastcall LoadGradeData(AnsiString gradeFileName, TTabletGradeData &GradeData)
{
	if (FileExists(gradeFileName))
    {
		TFileStream *fileStream = new TFileStream(gradeFileName, fmOpenRead);
	    if (fileStream)
	    {
			fileStream->Read(&GradeData, sizeof(TTabletGradeData));
	    	delete fileStream;
	        return true;
	    }
	    else
	    {
	    	return false;
	    }
    }
    else
    {
        return false;
    }
}
//---------------------------------------------------------------------------
bool __fastcall LoadStudyData(AnsiString studyFileName, TTabletStudyResultData &StudyData)
{
	if (FileExists(studyFileName))
    {
		TFileStream *fileStream = new TFileStream(studyFileName, fmOpenRead);
	    if (fileStream)
	    {
			fileStream->Read(&StudyData, sizeof(TTabletStudyData));
	    	delete fileStream;
	        return true;
	    }
	    else
	    {
	    	return false;
	    }
    }
    else
    {
        return false;
    }
}
//---------------------------------------------------------------------------
bool __fastcall SaveStudyData(AnsiString studyFileName, TTabletStudyResultData &StudyData)
{
	TFileStream *fileStream = new TFileStream(studyFileName, fmCreate);
    if (fileStream)
    {
		fileStream->Write(&StudyData, sizeof(TTabletStudyData));
    	delete fileStream;
        return true;
    }
    else
    {
    	return false;
    }
}
//---------------------------------------------------------------------------
float __fastcall ConvertDiscTimeToLength(int discIndex, int motorBaseSpeed, int discSpeedModifier, float time)
{
	int discDiameter[2];
    float discSpeed;
    discDiameter[0] = 102;
    discDiameter[1] = 202;

    discSpeed = motorBaseSpeed / 500.0 * 3 / 10;		// motor base speed / step count * gear ratio 

    float length = time / 1000 * discSpeed * discSpeedModifier / 100 * discDiameter[discIndex] * 3.141592;
	return length;
}
//---------------------------------------------------------------------------
float __fastcall ConvertDiscLengthToTime(int discIndex, int motorBaseSpeed, int discSpeedModifier, float length)
{
	int discDiameter[2];
    float discSpeed;
    discDiameter[0] = 102;
    discDiameter[1] = 202;

    discSpeed = motorBaseSpeed / 500.0 * 3 / 10;

    float time = length / (discDiameter[discIndex] * 3.141592) / (discSpeed * discSpeedModifier / 100) * 1000;
	return time;
}
//---------------------------------------------------------------------------

void __fastcall MakeTabletCharacterData(TProductData *productData,
	TTabletCharacter *tabletCharacter, TMachineParams *machineParams)
{
	switch (productData->TabletType)
    {
		case TABLET_TYPE_UNCOATED:
        	tabletCharacter->kind = UNCOATING;
            break;
		case TABLET_TYPE_FILM_COATED:
        	tabletCharacter->kind = FILMCOATING;
            break;
		case TABLET_TYPE_SUGAR_COATED:
        	tabletCharacter->kind = SUGARCOATING;
            break;
		default:
        	tabletCharacter->kind = UNCOATING;
            break;
    }

    switch (productData->TabletShape)
    {
		case TABLET_SHAPE_CIRCLE:
			tabletCharacter->shape = ROUND;
            break;
		case TABLET_SHAPE_OBLONG:
			tabletCharacter->shape = OBLONG;
            break;
		case TABLET_SHAPE_OVAL:
			tabletCharacter->shape = OVAL;
            break;
		case TABLET_SHAPE_HEXAGON:
			tabletCharacter->shape = HEXA;
            break;
		case TABLET_SHAPE_TRIANGLE:
			tabletCharacter->shape = TRIANGLE;
			break;
		case TABLET_SHAPE_SQUARE:
			tabletCharacter->shape = SQUARE;
			break;
		case TABLET_SHAPE_OCTAGON:
			tabletCharacter->shape = ETC;
			break;
		case TABLET_SHAPE_ETC:
			tabletCharacter->shape = ETC;
            break;
		default:
			tabletCharacter->shape = ROUND;
            break;
    }

	switch (productData->EngraveType)
    {
		case ENGRAVE_TYPE_RELIEF:
        	tabletCharacter->discriminationDisplay_kind = STAMP;
            break;
		case ENGRAVE_TYPE_INTAGLIO:
        	tabletCharacter->discriminationDisplay_kind = STAMP;
            break;
		case ENGRAVE_TYPE_PRINT:
        	tabletCharacter->discriminationDisplay_kind = PRINT;
            break;
        default:
        	tabletCharacter->discriminationDisplay_kind = STAMP;
            break;
    }

    switch (productData->EngravePos)
    {
		case ENGRAVE_POS_ONESIDE:
			tabletCharacter->discriminationDisplay_num = ONE_FACE;
            break;
		case ENGRAVE_POS_SAME:
			tabletCharacter->discriminationDisplay_num = TWO_FACE_SAME;
            break;
        default:
        	tabletCharacter->discriminationDisplay_num = TWO_FACE_DIFF;
            break;
    }

	if (productData->PlateTablet)
	{
		tabletCharacter->plateInformation = 1;
	}
	else
	{
		tabletCharacter->plateInformation = 0;
	}

	if (productData->Arrange)
	{
		tabletCharacter->arrangeInfo = ARRANGE;
	}
	else
	{
		tabletCharacter->arrangeInfo = NOT_ARRANGE;
	}

	tabletCharacter->symmetric_line_count = productData->SymmetricLineCount;
	tabletCharacter->length = productData->TabletLength * 10000 / machineParams->CameraResolution[0];
	tabletCharacter->width = productData->TabletWidth * 10000  / machineParams->CameraResolution[0];
   	tabletCharacter->middle_height = productData->TabletSideThick * 10000  / machineParams->CameraResolution[0];
	tabletCharacter->height = productData->TabletThick * 10000  / machineParams->CameraResolution[0];

	if (productData->TabletType != TABLET_TYPE_MULTI_LAYERED)
	{
		tabletCharacter->tabletLayerCount = 1;
        tabletCharacter->tabletColorN = ONECOLOR;
	}
	else
	{
		tabletCharacter->tabletLayerCount = productData->TabletLayerCount;
        if (productData->MultiLayeredTabletColor[0] != productData->MultiLayeredTabletColor[productData->TabletLayerCount - 1])
        {
            tabletCharacter->tabletColorN = TWOCOLOR;
        }
        else
        {
            tabletCharacter->tabletColorN = ONECOLOR;
        }
	}

}
//---------------------------------------------------------------------------
WideString __fastcall GetDefectSeriesStr(int series)
{

}
//---------------------------------------------------------------------------
bool __fastcall SaveShutterSpeedInfo(AnsiString fileName, AnsiString colorCodeName, TColor bgrColor, int *shutterSpeedList, unsigned int validCameraMask)
{
    TIniFile *iniFile = new TIniFile(fileName);
    if (iniFile)
    {
    	// does same color table exists?
        TStringList *colorTableList = new TStringList;
    	iniFile->ReadSections(colorTableList);
        for (int tableIndex = 0; tableIndex < colorTableList->Count; tableIndex++)
        {
        	AnsiString existColorCodeName = colorTableList->Strings[tableIndex];
			TColor existColor = iniFile->ReadInteger(existColorCodeName, "BGR Value", 0);
			if (existColor == bgrColor)
            {
				iniFile->EraseSection(existColorCodeName);
            }
        }
        delete colorTableList;

        iniFile->WriteInteger(colorCodeName, "BGR Value", bgrColor);

		for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
		{
			if (validCameraMask & (0x0001 << globalCameraIndex))
			{
				iniFile->WriteInteger(colorCodeName, "Shutter Speed" + IntToStr(globalCameraIndex + 1), shutterSpeedList[globalCameraIndex]);
			}
        }

    	delete iniFile;
		return true;
    }
    else
    {
		return false;
    }
}
//---------------------------------------------------------------------------
AnsiString __fastcall LoadShutterSpeedInfo(AnsiString fileName, AnsiString colorCodeName, TColor bgrColor, int *shutterSpeedList, unsigned int validCameraMask)
{
	TIniFile *iniFile = new TIniFile(fileName);
    AnsiString returnCodeName = "";
    if (iniFile)
    {
    	bool bColorCodeNameExist = false;
        TColor similarColor = 0xFFFFFF;
        AnsiString similarColorCodeName = "";
        int minColorSimilarity;
    	// does same color table exists?
        TStringList *colorTableList = new TStringList;
    	iniFile->ReadSections(colorTableList);
        for (int tableIndex = 0; tableIndex < colorTableList->Count; tableIndex++)
        {
        	AnsiString existColorCodeName = colorTableList->Strings[tableIndex];
			if (existColorCodeName == colorCodeName)
            {
				bColorCodeNameExist = true;
                break;
            }
            else
            {
            	TColor existColor = iniFile->ReadInteger(existColorCodeName, "BGR Value", 0);
                int bgrColorR = (bgrColor >>  0) & 0xFF;
                int bgrColorG = (bgrColor >>  8) & 0xFF;
                int bgrColorB = (bgrColor >> 16) & 0xFF;
                int existColorR = (existColor >>  0) & 0xFF;
                int existColorG = (existColor >>  8) & 0xFF;
                int existColorB = (existColor >> 16) & 0xFF;
                int similarity = sqrt(((bgrColorR - existColorR) * (bgrColorR - existColorR) + (bgrColorG - existColorG) * (bgrColorG - existColorG) +
                	(bgrColorB - existColorB) * (bgrColorB - existColorB)) / 3) +
                    abs(bgrColorR + bgrColorG + bgrColorB - existColorR - existColorG - existColorB) / 3;
				if (similarColorCodeName == "")
                {
					similarColorCodeName = existColorCodeName;
                    minColorSimilarity = similarity;
                }
                else if (minColorSimilarity > similarity)
                {
					similarColorCodeName = existColorCodeName;
                    minColorSimilarity = similarity;
                }
            }
        }

        if (colorTableList->Count == 0)
        {
			returnCodeName = "";
        }
        else if (bColorCodeNameExist)
        {
			returnCodeName = colorCodeName;
			for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
			{
				if (validCameraMask & (0x0001 << globalCameraIndex))
				{
					shutterSpeedList[globalCameraIndex] = iniFile->ReadInteger(colorCodeName, "Shutter Speed" + IntToStr(globalCameraIndex + 1), 10);
				}
	        }
        }
        else
        {
			returnCodeName = similarColorCodeName;
			for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
			{
				if (validCameraMask & (0x0001 << globalCameraIndex))
				{
					shutterSpeedList[globalCameraIndex] = iniFile->ReadInteger(similarColorCodeName, "Shutter Speed" + IntToStr(globalCameraIndex + 1), 10);
				}
	        }
        }

        delete colorTableList;
    	delete iniFile;
    }
    else
    {
    }
	return returnCodeName;
}
//---------------------------------------------------------------------------
AnsiString __fastcall Load3DParameterInfo(AnsiString fileName, AnsiString colorCodeName, TColor bgrColor, int *exposureTimeList, int *thresholdList, unsigned int validCameraMask)
{
	int colorGradeValue = (((bgrColor & 0xFF) * 8 + ((bgrColor >> 8) & 0xFF) + ((bgrColor >> 16) & 0xFF)) + 128) / 256;		// 11 grades

	int exposureTimePerGrade[11] = {20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10};
	int thresholdPerGrade[11] = {20, 20, 25, 25, 25, 20, 20, 25, 30, 35, 40};

	for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	{
		if (validCameraMask & (0x0001 << globalCameraIndex))
		{
			exposureTimeList[globalCameraIndex] = exposureTimePerGrade[colorGradeValue];
			thresholdList[globalCameraIndex] = thresholdPerGrade[colorGradeValue];
		}
	}
/*
	TIniFile *iniFile = new TIniFile(fileName);
    AnsiString returnCodeName = "";
	if (iniFile)
    {
		bool bColorCodeNameExist = false;
        TColor similarColor = 0xFFFFFF;
        AnsiString similarColorCodeName = "";
        int minColorSimilarity;
    	// does same color table exists?
        TStringList *colorTableList = new TStringList;
    	iniFile->ReadSections(colorTableList);
        for (int tableIndex = 0; tableIndex < colorTableList->Count; tableIndex++)
        {
        	AnsiString existColorCodeName = colorTableList->Strings[tableIndex];
			if (existColorCodeName == colorCodeName)
            {
				bColorCodeNameExist = true;
                break;
            }
            else
            {
            	TColor existColor = iniFile->ReadInteger(existColorCodeName, "BGR Value", 0);
                int bgrColorR = (bgrColor >>  0) & 0xFF;
				int existColorR = (existColor >>  0) & 0xFF;
				int similarity = abs(bgrColorR - existColorR);
				if (similarColorCodeName == "")
                {
					similarColorCodeName = existColorCodeName;
                    minColorSimilarity = similarity;
                }
                else if (minColorSimilarity > similarity)
                {
					similarColorCodeName = existColorCodeName;
                    minColorSimilarity = similarity;
                }
            }
        }

        if (colorTableList->Count == 0)
        {
			returnCodeName = "";
        }
        else if (bColorCodeNameExist)
        {
			returnCodeName = colorCodeName;
			for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
			{
				if (validCameraMask & (0x0001 << globalCameraIndex))
				{
					exposureTimeList[globalCameraIndex] = iniFile->ReadInteger(colorCodeName, "Exposure Time" + IntToStr(globalCameraIndex + 1), 10);
					thresholdList[globalCameraIndex] = iniFile->ReadInteger(colorCodeName, "Threshold" + IntToStr(globalCameraIndex + 1), 30);
				}
			}
		}
		else
		{
			returnCodeName = similarColorCodeName;
			for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
			{
				if (validCameraMask & (0x0001 << globalCameraIndex))
				{
					exposureTimeList[globalCameraIndex] = iniFile->ReadInteger(similarColorCodeName, "Shutter Speed" + IntToStr(globalCameraIndex + 1), 10);
					thresholdList[globalCameraIndex] = iniFile->ReadInteger(similarColorCodeName, "Threshold" + IntToStr(globalCameraIndex + 1), 30);
				}
	        }
        }

        delete colorTableList;
    	delete iniFile;
    }
    else
	{
	}
	return returnCodeName;
*/
	return "";
}
//---------------------------------------------------------------------------
bool __fastcall IsLargeTablet(TProductData &productData)
{
	bool bLargeTablet = false;
    if (productData.TabletThick >= LARGE_TABLET_CIRCLE_THICK)
    {
    	bLargeTablet = true;
    }
    if (productData.TabletShape == TABLET_SHAPE_CIRCLE)
    {
    	if (productData.TabletLength >= LARGE_TABLET_CIRCLE_LENGTH)
        {
        	bLargeTablet = true;
        }
    }
    else
    {
    	if (productData.TabletLength >= LARGE_TABLET_OBLONG_LENGTH)
        {
        	bLargeTablet = true;
        }
    }

    return bLargeTablet;
}
//---------------------------------------------------------------------------
WideString __fastcall TabletKindStr(int tabletKind)
{
    switch (tabletKind)
    {
		case TABLET_TYPE_UNCOATED:
        	return COMMONPC_RETURNSTR_05;
            break;
        case TABLET_TYPE_FILM_COATED:
        	return COMMONPC_RETURNSTR_44;
            break;
		case TABLET_TYPE_SUGAR_COATED:
			return COMMONPC_RETURNSTR_01;
			break;
		case TABLET_TYPE_MULTI_LAYERED:
			return COMMONPC_RETURNSTR_06;
			break;
        case TABLET_TYPE_UNKNOWN:
        default:
			return COMMONPC_RETURNSTR_02;
            break;
    }
}
//---------------------------------------------------------------------------
WideString __fastcall TabletShapeStr(int tabletShape)
{
    switch (tabletShape)
    {
		case TABLET_SHAPE_CIRCLE:
        	return COMMONPC_RETURNSTR_27;
            break;
        case TABLET_SHAPE_OBLONG:
        	return COMMONPC_RETURNSTR_33;
            break;
        case TABLET_SHAPE_OVAL:
        	return COMMONPC_RETURNSTR_43;
            break;
        case TABLET_SHAPE_HEXAGON:
	        return COMMONPC_RETURNSTR_35;
            break;
        case TABLET_SHAPE_TRIANGLE:
	        return COMMONPC_RETURNSTR_34;
			break;
		case TABLET_SHAPE_SQUARE:
			return "정사각형";
			break;
		case TABLET_SHAPE_OCTAGON:
			return COMMONPC_RETURNSTR_39;
			break;
		case TABLET_SHAPE_ETC:
        	return "기타";
            break;
        case TABLET_SHAPE_UNKNOWN:
        default:
			return COMMONPC_RETURNSTR_20;
            break;
    }

}
//---------------------------------------------------------------------------
WideString __fastcall TabletEngraveKindStr(int engraveKind)
{
	switch (engraveKind)
	{
		case ENGRAVE_TYPE_UNKNOWN:
			return COMMONPC_RETURNSTR_20;
		case ENGRAVE_TYPE_RELIEF:
			return COMMONPC_RETURNSTR_22;
		case ENGRAVE_TYPE_INTAGLIO:
			return COMMONPC_RETURNSTR_28;
		case ENGRAVE_TYPE_PRINT:
			return COMMONPC_RETURNSTR_29;
		case ENGRAVE_TYPE_EMPTY:
			return COMMONPC_RETURNSTR_25;
		default:
			return COMMONPC_RETURNSTR_20;
	}
}
//---------------------------------------------------------------------------
WideString __fastcall TabletEngravePosStr(int engravePos)
{
	switch (engravePos)
	{
		case ENGRAVE_POS_UNKNOWN:
			return COMMONPC_RETURNSTR_20;
		case ENGRAVE_POS_ONESIDE:
			return COMMONPC_RETURNSTR_45;
		case ENGRAVE_POS_SAME:
			return COMMONPC_RETURNSTR_23;
		case ENGRAVE_POS_DIFF:
			return COMMONPC_RETURNSTR_24;
		default:
			return COMMONPC_RETURNSTR_20;
	}
}
//---------------------------------------------------------------------------
WideString __fastcall LampKindStr(int lampKind)
{
	switch (lampKind)
	{
		case MACHINE_LAMP_KIND_NORMAL_TABLET:
			return COMMONPC_RETURNSTR_03;
		case MACHINE_LAMP_KIND_SUGAR_COATED_TABLET:
			return COMMONPC_RETURNSTR_01;
		default:
			return COMMONPC_RETURNSTR_02;
	}
}
//---------------------------------------------------------------------------
bool __fastcall ReadUserMachineEnvData(AnsiString fileName, TUserMachineEnv &userMachineEnv)
{
	memset(&userMachineEnv, 0, sizeof(TUserMachineEnv));
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		userMachineEnv.Enabled = iniFile->ReadInteger("Dust Blower Sol", "Global Enabled", 1);
		userMachineEnv.DustBlower1Interval = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 1 Interval", 60000);
		userMachineEnv.DustBlower2Interval = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 2 Interval", 60000);
		userMachineEnv.DustBlower3Interval = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 3 Interval", 60000);
		userMachineEnv.DustBlower4Interval = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 4 Interval", 60000);
		userMachineEnv.DustBlower5Interval = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 5 Interval", 60000);
		userMachineEnv.DustBlower1Delay = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 1 Delay", 0);
		userMachineEnv.DustBlower2Delay = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 2 Delay", 12000);
		userMachineEnv.DustBlower3Delay = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 3 Delay", 24000);
		userMachineEnv.DustBlower4Delay = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 4 Delay", 36000);
		userMachineEnv.DustBlower5Delay = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 5 Delay", 48000);
		userMachineEnv.DustBlower1BlowTime = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 1 Blow Time", 1000);
		userMachineEnv.DustBlower2BlowTime = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 2 Blow Time", 1000);
		userMachineEnv.DustBlower3BlowTime = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 3 Blow Time", 1000);
		userMachineEnv.DustBlower4BlowTime = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 4 Blow Time", 1000);
		userMachineEnv.DustBlower5BlowTime = iniFile->ReadInteger("Dust Blower Sol", "Dust Blower 5 Blow Time", 1000);
		delete iniFile;
    }
    else
    {
        return false;
    }
    return true;
}
//---------------------------------------------------------------------------
bool __fastcall WriteUserMachineEnvData(AnsiString fileName, TUserMachineEnv &userMachineEnv)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
    {
        iniFile->WriteInteger("Dust Blower Sol", "Global Enabled", userMachineEnv.Enabled);
	    iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 1 Interval", userMachineEnv.DustBlower1Interval);
        iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 2 Interval", userMachineEnv.DustBlower2Interval);
        iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 3 Interval", userMachineEnv.DustBlower3Interval);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 4 Interval", userMachineEnv.DustBlower4Interval);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 5 Interval", userMachineEnv.DustBlower5Interval);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 1 Delay", userMachineEnv.DustBlower1Delay);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 2 Delay", userMachineEnv.DustBlower2Delay);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 3 Delay", userMachineEnv.DustBlower3Delay);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 4 Delay", userMachineEnv.DustBlower4Delay);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 5 Delay", userMachineEnv.DustBlower5Delay);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 1 Blow Time", userMachineEnv.DustBlower1BlowTime);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 2 Blow Time", userMachineEnv.DustBlower2BlowTime);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 3 Blow Time", userMachineEnv.DustBlower3BlowTime);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 4 Blow Time", userMachineEnv.DustBlower4BlowTime);
		iniFile->WriteInteger("Dust Blower Sol", "Dust Blower 5 Blow Time", userMachineEnv.DustBlower5BlowTime);
        delete iniFile;
    }
    else
    {
        return false;
    }
    return true;
}
//---------------------------------------------------------------------------
void __fastcall InitCommon_PC(void)
{
    for(int m = 0; m < 1000; m++)
    {
        Table_Interval_PixelAndMeter[m] = (int) (5.73 * (float)(m* m)/100.0);
    }
}
//---------------------------------------------------------------------------
int  __fastcall DefectSizePixelToMili(int pixel)
{
    int closeMili = 0;
    int min  = 10000000;
    for(int m = 0; m < 1000; m++)
    {
        if( abs(pixel - Table_Interval_PixelAndMeter[m]) < min)
        {
            min = abs(pixel - Table_Interval_PixelAndMeter[m]);
            closeMili = m;
        }
    }
    return(closeMili);
}
//---------------------------------------------------------------------------
int  __fastcall GetDefaultGuideKind(int guideIndex, double tabletWidth)
{
	if (tabletWidth <= 6.3)
	{
		return 6;
	}
	else if (tabletWidth <= 7.3)
	{
		return 7;
	}
	else if (tabletWidth <= 8.3)
	{
		return 8;
	}
	else if (tabletWidth <= 9.3)
	{
		return 9;
	}
	else if (tabletWidth <= 10.3)
	{
		return 10;
	}
	else
	{
		return 11;
	}
}
//---------------------------------------------------------------------------
int  __fastcall GetDefaultVGateKind(int gateIndex, double tabletWidth)
{
	if (tabletWidth <= 6.3)
	{
		return 6;
	}
	else if (tabletWidth <= 7.3)
	{
		return 7;
	}
	else if (tabletWidth <= 8.3)
	{
		return 8;
	}
	else if (tabletWidth <= 9.3)
	{
		return 9;
	}
	else if (tabletWidth <= 10.3)
	{
		return 10;
	}
	else
	{
		return 11;
	}
}
//---------------------------------------------------------------------------
int __fastcall GetDefaultAirKnifeSpeed(void)
{
	return 2;
}
//---------------------------------------------------------------------------
int __fastcall GetDefaultSuctionSpeed(TProductData &productData, int &suctionSpeed1, int &suctionSpeed2)
{
	if (IsLargeTablet(productData))
	{
		suctionSpeed1 = 255;
		suctionSpeed2 = 255;
	}
	else
	{
//		suctionSpeed1 = 200;
//		suctionSpeed2 = 200;
		suctionSpeed1 = 255;
		suctionSpeed2 = 255;
	}
}
//---------------------------------------------------------------------------
bool __fastcall ReadDSMInfo(AnsiString fileName, TDSMInfo &dsmInfo)
{
	bool dataExists = false;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		dataExists = iniFile->ReadBool("Information", "Data Exists", false);
		dsmInfo.DSMEnabled = iniFile->ReadBool("Information", "Enabled", dataExists);
//		dsmInfo.OldDataCompress = iniFile->ReadBool("Information", "Old Data Compress", false);
//		dsmInfo.BMPMaintainTime = iniFile->ReadFloat("Information", "BMP Maintain Time", 10.0);
		dsmInfo.ReduceTime[0] = iniFile->ReadFloat("Information", "Reduce Time 1", 0);
		dsmInfo.ReduceTime[1] = iniFile->ReadFloat("Information", "Reduce Time 2", 90);
		dsmInfo.ReduceTime[2] = iniFile->ReadFloat("Information", "Reduce Time 3", 365);
		dsmInfo.PrimeLotCount[0] = iniFile->ReadInteger("Information", "Prime Lot Count 1", 2);
		dsmInfo.PrimeLotCount[1] = iniFile->ReadInteger("Information", "Prime Lot Count 2", 2);
		dsmInfo.PrimeLotCount[2] = iniFile->ReadInteger("Information", "Prime Lot Count 3", 2);
		dsmInfo.PrimeLotMaxDefectCount[0] = iniFile->ReadInteger("Information", "Prime Lot Max Defect Count 1", -1);
		dsmInfo.PrimeLotMaxDefectCount[1] = iniFile->ReadInteger("Information", "Prime Lot Max Defect Count 2", 1000);
		dsmInfo.PrimeLotMaxDefectCount[2] = iniFile->ReadInteger("Information", "Prime Lot Max Defect Count 3", 100);
		dsmInfo.TrivialLotMaxDefectCount[0] = iniFile->ReadInteger("Information", "Trivial Lot Max Defect Count 1", 1000);
		dsmInfo.TrivialLotMaxDefectCount[1] = iniFile->ReadInteger("Information", "Trivial Lot Max Defect Count 2", 100);
		dsmInfo.TrivialLotMaxDefectCount[2] = iniFile->ReadInteger("Information", "Trivial Lot Max Defect Count 3", 0);
		dsmInfo.MinDiskSpaceRatio = iniFile->ReadInteger("Information", "Min Disk Space Ratio", 10);
		dsmInfo.DSMAlwaysOn = iniFile->ReadBool("Information", "DSM Always On", true);
		dsmInfo.DSMStartTime.Val = iniFile->ReadFloat("Information", "DSM Start Time", 0.5);
		dsmInfo.DSMEndTime.Val = iniFile->ReadFloat("Information", "DSM End Time", 0.6);
		delete iniFile;
		return dsmInfo.DSMEnabled;
	}
	else
	{
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
void __fastcall WriteDSMInfo(AnsiString fileName, TDSMInfo &dsmInfo)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteBool("Information", "Data Exists", true);
		iniFile->WriteBool("Information", "Enabled", dsmInfo.DSMEnabled);
//		iniFile->WriteBool("Information", "Old Data Compress", dsmInfo.OldDataCompress);
//		iniFile->WriteFloat("Information", "BMP Maintain Time", dsmInfo.BMPMaintainTime);
		iniFile->WriteFloat("Information", "Reduce Time 1", dsmInfo.ReduceTime[0]);
		iniFile->WriteFloat("Information", "Reduce Time 2", dsmInfo.ReduceTime[1]);
		iniFile->WriteFloat("Information", "Reduce Time 3", dsmInfo.ReduceTime[2]);
		iniFile->WriteInteger("Information", "Prime Lot Count 1", dsmInfo.PrimeLotCount[0]);
		iniFile->WriteInteger("Information", "Prime Lot Count 2", dsmInfo.PrimeLotCount[1]);
		iniFile->WriteInteger("Information", "Prime Lot Count 3", dsmInfo.PrimeLotCount[2]);
		iniFile->WriteInteger("Information", "Prime Lot Max Defect Count 1", dsmInfo.PrimeLotMaxDefectCount[0]);
		iniFile->WriteInteger("Information", "Prime Lot Max Defect Count 2", dsmInfo.PrimeLotMaxDefectCount[1]);
		iniFile->WriteInteger("Information", "Prime Lot Max Defect Count 3", dsmInfo.PrimeLotMaxDefectCount[2]);
		iniFile->WriteInteger("Information", "Trivial Lot Max Defect Count 1", dsmInfo.TrivialLotMaxDefectCount[0]);
		iniFile->WriteInteger("Information", "Trivial Lot Max Defect Count 2", dsmInfo.TrivialLotMaxDefectCount[1]);
		iniFile->WriteInteger("Information", "Trivial Lot Max Defect Count 3", dsmInfo.TrivialLotMaxDefectCount[2]);
		iniFile->WriteInteger("Information", "Min Disk Space Ratio", dsmInfo.MinDiskSpaceRatio);
		iniFile->WriteBool("Information", "DSM Always On", dsmInfo.DSMAlwaysOn);
		iniFile->WriteFloat("Information", "DSM Start Time", dsmInfo.DSMStartTime.Val);
		iniFile->WriteFloat("Information", "DSM End Time", dsmInfo.DSMEndTime.Val);
		delete iniFile;
	}
}
//---------------------------------------------------------------------------
void __fastcall ImageConversion_3D(Graphics::TBitmap *DestBitmap, int destWidth, int destHeight,
	byte *srcBitmap, int srcWidth, int srcHeight)
{
	for (int y = 0; y < destHeight; y++)
	{
		byte *pBitmap = (byte *)DestBitmap->ScanLine[y];
		for (int x = 0; x < destWidth; x++)
		{
			pBitmap[x] = srcBitmap[x * srcWidth + y];
		}
	}
}
//---------------------------------------------------------------------------
int __fastcall GetMSTabletTypeIndex(int tabletType)
{
	int returnValue = 0;
	if (tabletType == TABLET_TYPE_UNCOATED)
	{
		returnValue = 0;
	}
	else if (tabletType == TABLET_TYPE_FILM_COATED)
	{
		returnValue = 1;
	}
	else if (tabletType == TABLET_TYPE_SUGAR_COATED)
	{
		returnValue = 2;
	}
	else if (tabletType == TABLET_TYPE_MULTI_LAYERED)
	{
		returnValue = 0; // treat as uncoated
	}
	return returnValue;
}
//---------------------------------------------------------------------------
int __fastcall GetMSTabletShapeIndex(int tabletShape)
{
	int returnValue = 0;
	if (tabletShape == TABLET_SHAPE_CIRCLE)
	{
		returnValue = 0;
	}
	else if (tabletShape == TABLET_SHAPE_OBLONG)
	{
		returnValue = 1;
	}
	else if (tabletShape == TABLET_SHAPE_OVAL)
	{
		returnValue = 2;
	}
	else
	{
		returnValue = 3;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
unsigned short Generate_CRC16(unsigned char *data, int len)
{
	const unsigned char abCrcHi[] =
	{
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
		0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
	};

	const unsigned char abCrcLo[] =
	{
		0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04,
		0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8,
		0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
		0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10,
		0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
		0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,	0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
		0x28, 0xE8, 0xE9, 0x29,	0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,	0xEC, 0x2C,
		0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,	0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0,
		0xA0, 0x60,	0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,	0xA5, 0x65, 0x64, 0x44,
		0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,	0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
		0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C,
		0xB4, 0x74, 0x75, 0xB5,	0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,	0x70, 0xB0,
		0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,	0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54,
		0x9C, 0x5C,	0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,	0x99, 0x59, 0x58, 0x98,
		0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,	0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
		0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,	0x43, 0x83, 0x41, 0x81, 0x80, 0x40
	};

	unsigned char bCrcHi = 0xFF;
	unsigned char bCrcLo = 0xFF;
	unsigned short index;
	unsigned char *pData = data;

	int length = len;
	while (length--)
	{
		index = bCrcHi ^ *pData++;
		bCrcHi = bCrcLo ^ abCrcHi[index];
		bCrcLo = abCrcLo[index];
	}
	return (bCrcHi << 8 | bCrcLo);
}
//---------------------------------------------------------------------------
void __fastcall GetDefaultNCPosition(TProductData &productData, double *ncMotorPos, double interlockAValue)
{
	double N = productData.RotatingGuideKind;
	double R = productData.TabletWidth;
	double W = productData.TabletWidth;
	double L = productData.TabletLength;
	double H = productData.TabletThick;
	double Hc = (productData.TabletThick - productData.TabletSideThick) / 2;
	double Dsd = 0;

	if (productData.TabletType == TABLET_TYPE_SUGAR_COATED)
	{
		Hc = productData.TabletThick / 6;
	}

	if (productData.TabletShape == TABLET_SHAPE_OBLONG)
	{
		if (!productData.PlateTablet)
		{
			ncMotorPos[VG1_UP_DOWN_MOTOR_INDEX] = H - 0.1 +	(W - H - 1) / 10;
			ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] = H - 0.2;
		}
		else
		{
			ncMotorPos[VG1_UP_DOWN_MOTOR_INDEX] = H + 0.1;
			ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] = H;
		}

		if (W > 0)
		{
			Dsd = H - (1.5 / sqrt(W) + Hc / 2);
		}
		else
		{
			Dsd = H;
		}
		ncMotorPos[BF_IN_OUT_MOTOR_INDEX] = (N - 6) / 2 + (N - W) / 2 + H * 0.1 + L / 2 * 0.1;
	}
	else if (productData.TabletShape == TABLET_SHAPE_OVAL)
	{
		if (!productData.PlateTablet)
		{
			ncMotorPos[VG1_UP_DOWN_MOTOR_INDEX] = H - 0.1;
			ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] = H - 0.3;
		}
		else
		{
			ncMotorPos[VG1_UP_DOWN_MOTOR_INDEX] = H;
			ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] = H;
		}

		if (W > 0)
		{
			Dsd = H - (1.6 / sqrt(W) + 5 * Hc / W);
		}
		else
		{
			Dsd = H;
		}
		ncMotorPos[BF_IN_OUT_MOTOR_INDEX] = (N - 6) / 2 + (N - W) / 2 + H * 0.1 + 0.1;
	}
	else // cirle or other shape
	{
		if (!productData.PlateTablet)
		{
			ncMotorPos[VG1_UP_DOWN_MOTOR_INDEX] = H;
			ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] = H - 0.2;
		}
		else
		{
			ncMotorPos[VG1_UP_DOWN_MOTOR_INDEX] = H + 0.2;
			ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] = H;
		}

		if (R > 0)
		{
			Dsd = H - (1.6 / sqrt(R) + 6 * Hc / R);
		}
		else
		{
			Dsd = H;
		}
		ncMotorPos[BF_IN_OUT_MOTOR_INDEX] = (N - 6) / 2 + (N - R) / 2 + H * 0.1 + (R - 6) * 0.1;
	}

	double suctionDisk2Position = sqrt((SUCTION_DISK_DIAMETER + Dsd) * (SUCTION_DISK_DIAMETER + Dsd) - SUCTION_DISK_DISTANCE_Y * SUCTION_DISK_DISTANCE_Y) - SUCTION_DISK_DISTANCE_BASE_X;
	ncMotorPos[SD2_LEFT_RIGHT_MOTOR_INDEX] = suctionDisk2Position;
	ncMotorPos[VG2_UP_DOWN_MOTOR_INDEX] = interlockAValue + ncMotorPos[BF_UP_DOWN_MOTOR_INDEX] - 0.1;
}
//---------------------------------------------------------------------------
void __fastcall CopyProductData(TProductData &dest, TProductData &src)
{
	dest.ProductCode = src.ProductCode;
	dest.ProductName = src.ProductName;
	dest.LOTName = src.LOTName;
	dest.TabletType = src.TabletType;
	dest.TabletShape = src.TabletShape;
	dest.StudyStep = src.StudyStep;
	dest.TabletLength = src.TabletLength;
	dest.TabletWidth = src.TabletWidth;
	dest.TabletThick = src.TabletThick;
	dest.TabletSideThick = src.TabletSideThick;
	dest.EngraveType = src.EngraveType;
	dest.EngravePos = src.EngravePos;
	dest.PrintBrightness = src.PrintBrightness;
	for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	{
		dest.BoundaryLeft[globalCameraIndex] = src.BoundaryLeft[globalCameraIndex];
		dest.BoundaryTop[globalCameraIndex] = src.BoundaryTop[globalCameraIndex];
		dest.BoundaryRight[globalCameraIndex] = src.BoundaryRight[globalCameraIndex];
		dest.BoundaryBottom[globalCameraIndex] = src.BoundaryBottom[globalCameraIndex];
		dest.ShutterSpeed[globalCameraIndex] = src.ShutterSpeed[globalCameraIndex];
		dest.ThresholdFor3D[globalCameraIndex] = src.ThresholdFor3D[globalCameraIndex];
	}
	dest.ProcessingStep = src.ProcessingStep;
	dest.TabletColorCode = src.TabletColorCode;
	dest.PrintColorCode = src.PrintColorCode;
	for (int motorIndex = 0; motorIndex < MAX_SERVO_MOTOR_COUNT; motorIndex++)
	{
		for (int speedIndex = 0; speedIndex < MOTOR_SPEED_STEP_COUNT_FOR_PRODUCT; speedIndex++)
		{
			dest.MotorSpeedList[motorIndex][speedIndex] = src.MotorSpeedList[motorIndex][speedIndex];
		}
	}
	dest.ProductionCount = src.ProductionCount;
	dest.LastInspectionTime = src.LastInspectionTime;
	dest.PlateTablet = src.PlateTablet;
	dest.Arrange = src.Arrange;
	dest.SymmetricLineCount = src.SymmetricLineCount;

	dest.TabletLayerCount = src.TabletLayerCount;

	for (int layerIndex = 0; layerIndex < MAX_TABLET_LAYER_COUNT; layerIndex++)
	{
		dest.MultiLayeredTabletColor[layerIndex] = src.MultiLayeredTabletColor[layerIndex];
	}
	dest.MachineRunOption = src.MachineRunOption;
	dest.StudiedSensor1Length = src.StudiedSensor1Length;
	dest.StudiedSensor2Length = src.StudiedSensor2Length;
	dest.StudiedSensorIntervalA = src.StudiedSensorIntervalA;
	dest.StudiedSensorIntervalB = src.StudiedSensorIntervalB;
	for (int motorIndex = 0; motorIndex < MAX_STEP_MOTOR_COUNT; motorIndex++)
	{
		dest.NCMotorPos[motorIndex] = src.NCMotorPos[motorIndex];
	}
	dest.PartialCaptureMode = src.PartialCaptureMode;
	dest.RotatingGuideKind = src.RotatingGuideKind;
	dest.FixedGuideKind = src.FixedGuideKind;
	dest.VerticalGate2Kind = src.VerticalGate2Kind;
	dest.LampKind = src.LampKind;
}
//---------------------------------------------------------------------------


