/*
 * AXMIspAeAlgorithm.cpp
 * AEアルゴリズム演算処理
 *
 */
#include "AXMIspAeAlgorithm.hpp"
//#include "AXMIspAeDeviceControl.hpp"
#include "AXMImageSensor/imageSensorDrv.h"
#include "AXMIspTest/DSPCommon.h"
#include "AXMIspTest/adrs_base.h"
#include "AXMIspTest/reg_imageif.h"
#include "AXMIspTest/spad_map.h"

#include "AXMIspAf/AXMIspAfAlgorithm.hpp"		// debug用

#ifndef PARASOFT_CPPTEST
using namespace std;
#endif

#define judgeDayNightInThreshold( x )  ((x)->judgeMode == DAYNIGHT_JUDGE_LUMIX) ? \
					(luminance > (x)->dayNightInThre) : (gain < (x)->dayNightInThre)
#define judgeDayNightOutThreshold( x ) ((x)->judgeMode == DAYNIGHT_JUDGE_LUMIX) ? \
					(luminance < (x)->dayNightOutThre) : (gain > (x)->dayNightOutThre)

AXMIspAeBase::AXMIspAeBase() {
#ifndef PARASOFT_CPPTEST
  TAG = "AXMIspAeBase::";
  #ifndef COUT_DEBUG
  cout << TAG + "constructor" << endl;
  #endif
#endif
	AeDiff = 0L;
	for(int i = 0; i < 2 ; i++) {
		for(int j = 0; j < 4 ; j++) {
			st_AeDiff[i].AeDiffLog[j] = 0L;
		}
		st_AeDiff[i].AeDiffLogFlag = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
		st_AeDiff[i].AeDiffFrameNo = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	}
	DeadZoneThreshold = 0L;
	ControlValueExposureTime = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	ControlValueGain = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
#ifdef MECHA_IRIS
	ControlValueIris = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
#endif
	AbsoluteLuminanceValue = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	ExposureTime = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	GainSensor = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	GainISP = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
#ifdef MECHA_IRIS
	RoughIrisValue = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	FlagIrisRegion = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	irisNoChangeFrameCnt = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
#endif
	
#ifdef IMX662
	shutterSpeed = Exposure1PER60S;         // 1/60fps
#elif IMX415	// IMX662
	// IMX415用
	shutterSpeed = Exposure1PER30S;         // 1/30fps
#else	// IMX662
	// IMX412用
	shutterSpeed = Exposure1PER15S;         // 1/15fps
#endif	// IMX662
	irisCntl = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	slowShutter = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	noChangeControl = false;
	outOfLimit = false;

	ControlObject = CNTOBJ_SHUTSPED;

	ptrAeSettingRef = NULL;
	AeControlValue = 0;					// AeDiff / AeSpeed		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	OpdYAve = 0L;							// AE評価データ　12bit(整数部8bit,小数1桁4bit)
	
	beforeExposureTime = 10000L;		// 初期値100%	// 露光時間		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）

	shutterSpeedLower = Exposure1PER500S;	// 1/500fps 輝度の低い方を下限とする
#ifdef IMX662
	shutterSpeedUpper = Exposure1PER60S;	// 1/60fps  輝度の高い方を上限とする
#elif IMX415	// IMX662
	// IMX415用
	shutterSpeedUpper = Exposure1PER30S;	// 1/30fps  輝度の高い方を上限とする
#else	// IMX662
	// IMX412用
	shutterSpeedUpper = Exposure1PER15S;	// 1/15fps  輝度の高い方を上限とする
#endif	// IMX662
#ifdef GAIN_TUNE
	gain = 0;
	gainLower =  0;                    	// 0dB  輝度の低い方を下限とする
	gainUpper = 480;	// 48dB×10
	beforeExposureGain = 0;      		// 前回のGain		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
#else
	gain = 0;
	gainLower =  0;                    	// 0dB  輝度の低い方を下限とする
	gainUpper = 48;		// 48dB				// 輝度の高い方を上限とする
	beforeExposureGain = 0;      		// 前回のGain		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
#endif
	slowShutterLower = shutterSpeedUpper;	// 輝度の低い方を下限とする
	slowShutterUpper = Exposure1PER15S;		// 1fps 輝度の高い方を上限とする
	irisUpper = 0;       				// 1.4 輝度の高い方を上限とする		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	irisLower = IRIS_MAX;					// 16  輝度の低い方を下限とする
	AeTarget = 0L;							// AE目標値WDR実装に伴い追加
	ExposureRatio = 0x00000400;				// default 露光比率 16 0x40 * 16
	forceIrisOpenCnt = 0;					// 起動時のIris開放カウンタ
	dayNightMode = DAYNIGHT_MODE_DAY;		// DAY/NIGHTモード 初期値はDAYモード
	dayNightCount = 0;

#ifdef PARASOFT_CPPTEST
	absTh1 = 0;
	absTh2 = 0;
#endif

}

AXMIspAeBase::~AXMIspAeBase() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMIspAeBase::notifyAeAlgorithm(AXMIspAeSetting *obj) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "notifyAeAlgorithm" << endl;
  #endif
#endif
  ptrAeSettingRef = obj;

  if(obj != NULL){
  	if(obj->flickerEnable) {
	    shutterSpeedUpper = Exposure1PER100S;                        // 1/100fps
	    shutterSpeedLower = Exposure1PER100S;                        // 1/100fps
  	} else {
	    shutterSpeedUpper = obj->objAeChara.RangeExposureTimeLower;  // 1/60fps
	    shutterSpeedLower = obj->objAeChara.RangeExposureTimeUpper;  // 1/500fps
  	}

#ifdef GAIN_TUNE
    gainUpper = obj->objAeChara.RangeGain*10;
#else
    gainUpper = obj->objAeChara.RangeGain;
#endif
    slowShutterLower = shutterSpeedUpper;
    slowShutterUpper = obj->objAeChara.MaxSlowShutter;
    irisLower = IRIS_MAX;          // 16
    irisUpper = 0;       // 1.4		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    AeTarget = obj->objAeTarget.AeTarget;		// AE目標値WDR実装に伴い追加
		// LISRに設定が無いため不要
		/*
  	if(obj->AeMode == E_AeExposureRatioWDRMode || obj->AeMode == E_AeAutoWDRMode) {		// 露光比指定WDRモード or オートWDRモード
			SetReg32(RegMIX_MODE, 0x01100001);					// K.Kawachi 0x01100010 => 0x01100001 B24:always 1 B20:always 1 | B4: 0:short first | B0: 1:WDR mode
			ExposureRatio = obj->objAeWDRChara.ExposureRatio;
			if(ExposureRatio > 0x00000FFF) {
				ExposureRatio = 0x00000FFF;
			}

			SetReg32(RegMIX_EXP_RATIO, 
				(obj->objAeWDRChara.adjustThrLong << 16) | obj->objAeWDRChara.adjustExposureRatio);			//  B11-0:露光比率 明るくするためにC00 => 400に設定
			SetReg32(RegMIX_THR_SHORT, 0x00800000 | obj->objAeWDRChara.adjustThrShort);							// B11-00	THRESH_SHORT
      SetReg32(RegMIX_ERR_THR,   obj->objAeWDRChara.adjustThrErr);
  	}else{
   	  SetReg32(RegMIX_MODE, 0x01100000);								// K.Kawachi 0x01100010 => 0x01100001 B24:always 1 B20:always 1 | B4: 0:short first | B0: 0:linear mode
	    SetReg32(RegMIX_EXP_RATIO, 0x00000400);							//  B27-16:THRESH_LONG 0 | B11-0:露光比率 16倍
	    SetReg32(RegMIX_THR_SHORT, 0x00800000);							// B11-00	THRESH_SHORT 0
	    SetReg32(RegMIX_ERR_THR,   0x02000010);
  	}
		*/
  }
}

void AXMIspAeBase::CalcAeDiff(AEBANK aeBank) {
  int i;
  long AeDiffLong = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  long AbsAeDiffLong = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAeDiff" << endl;
  #endif
#endif
  if (ptrAeSettingRef != NULL) {
    // 4-2-1 偏差の定義
    AeDiff = OpdYAve - AeTarget;

    // 4-2-2 不感帯の処理 閾値を求める
    DeadZoneThreshold = AeTarget * ptrAeSettingRef->objAeConvAdj.DeadZoneIn;
  }

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << "AeTarget = ";
  AeTarget.print();
  cout << "DeadZoneIn = ";
  ptrAeSettingRef->objAeConvAdj.DeadZoneIn.print();
  cout << "DeadZoneThreshold=AeTarget * DeadZoneIn=";
  DeadZoneThreshold.print();
  #endif
#endif

// 4-2-2．不感帯の処理
	  // 偏差の絶対値を求める
	  AbsAeDiffLong = AeDiffLong = AeDiff.conv2Long();
	  if (AeDiffLong < 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	    //偏差が負値の場合
	    AbsAeDiffLong = -AbsAeDiffLong;  //符号反転
	  }

  if (AbsAeDiffLong <= DeadZoneThreshold.conv2Long()) {
    // 偏差≦閾値の場合
    AeDiff = 0;	//偏差を0にする		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  } else {
    if (AeDiffLong < 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
      //偏差が負値の場合
      AeDiff = -AbsAeDiffLong;	//符号反転
    } else {
      //偏差が正値の場合
      AeDiff = AbsAeDiffLong;
    }
  }
  //  for debug v v v
  	setAECalcData2(AeDiff.conv2Long());
  //  for debug ^ ^ ^

//4-2-3 安定化処理
    st_AeDiff[aeBank].AeDiffLog[st_AeDiff[aeBank].AeDiffFrameNo] = AeDiff;
    st_AeDiff[aeBank].AeDiffFrameNo = (st_AeDiff[aeBank].AeDiffFrameNo + 1) & 3;	// AeFrameNo:0縲鰀3		※コンパイラ都合によりenumから数値に変更（_ONE -> 1, _THREE -> 3）
    AeDiffLong = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  if (st_AeDiff[aeBank].AeDiffLogFlag >= 3) {
	  // 4フレーム分の偏差の平均を求める
	  for (i = 0; i < 4; ++i) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0, _FOUR -> 4）
	    long tmp = st_AeDiff[aeBank].AeDiffLog[i].conv2Long();
	    AeDiffLong += tmp;
	  }
	  if (AeDiffLong >= 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	    //偏差が正値の場合
	  	AeDiffLong = ((AeDiffLong + 2) >> 2);  // 4フレーム分の平均 少数第1位四捨五入		※コンパイラ都合によりenumから数値に変更（_TWO -> 2）
	  }else{
	    //偏差が負値の場合
	  	AeDiffLong = ((AeDiffLong - 2) / 4);  	// 4フレーム分の平均 少数第1位四捨五入		※コンパイラ都合によりenumから数値に変更（_TWO -> 2）
	  }
  }else if(st_AeDiff[aeBank].AeDiffLogFlag == 2){
	  // 3フレーム分の偏差の平均を求める
	  for (i = 0; i < 3; ++i) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	    long tmp = st_AeDiff[aeBank].AeDiffLog[i].conv2Long();
	    AeDiffLong += tmp;
	  }
	  if (AeDiffLong >= 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	    //偏差が正値の場合
		  AeDiffLong = ((AeDiffLong + 1) / 3);  // 3フレーム分の平均 少数第1位四捨五入
	  }else{
	    //偏差が負値の場合
		  AeDiffLong = ((AeDiffLong - 1) / 3);  // 3フレーム分の平均 少数第1位四捨五入
	  }
	  st_AeDiff[aeBank].AeDiffLogFlag ++;
  } else {	// 1,2回目は何もしない
	  if(st_AeDiff[aeBank].AeDiffLogFlag == 1){
		  AeDiffLong = AeDiff.conv2Long();
	  }else{
	    st_AeDiff[aeBank].AeDiffLog[3] = AeDiff;	// Iris制御で１回前のAeDiffとの差分を計算するため一番最初は０になるように末にAeDiffを入れる
	  }
	  st_AeDiff[aeBank].AeDiffLogFlag ++;
  }
  AeDiff = AeDiffLong;

//  for debug v v v
	setAECalcData(AeDiff.conv2Long());
//  for debug ^ ^ ^

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << "AeDiff=";
  AeDiff.print();
  #endif
#endif
}

void AXMIspAeBase::CalcAeControlValue(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAeControlValue" << endl;
  #endif
#endif
  // AE設定情報が通知されているかチェックする
  if (ptrAeSettingRef != NULL) {
    AXMIspAeValue lAeTarget = AeTarget;
    AXMIspAeValue lAeTargetQuarter;
    lAeTargetQuarter.set(lAeTarget.conv2Long() >> 2);		// ※コンパイラ都合によりenumから数値に変更（_TWO -> 2）

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
    cout << "lAeTarget=";
    lAeTarget.print();
    cout << "lAeTargetQuarter=";
    lAeTargetQuarter.print();
  #endif
#endif
    LONG aeSpeed = static_cast<LONG>(ptrAeSettingRef->objAeConvAdj.AeSpeed);	// ULONG → LONG修正
#ifdef IMX662
  	LONG st_frm = (shutterSpeed + (Exposure1PER60S - 1)) / Exposure1PER60S;
#elif IMX415	// IMX662
	// IMX415用
  	LONG st_frm = (shutterSpeed + (Exposure1PER30S - 1)) / Exposure1PER30S;
#else	// IMX662
	// IMX412用
  	LONG st_frm = (shutterSpeed + (Exposure1PER15S - 1)) / Exposure1PER15S;
#endif	// IMX662

  	if (st_frm <= 0){
  		st_frm = 1;
  	}
  	if (aeSpeed >= st_frm){
		aeSpeed = aeSpeed / st_frm;
  	}else{
		aeSpeed = 1;
  	}
  	if(aeSpeed < 10) {
		aeSpeed = 10;
  	}
    long lAeDiff = AeDiff.conv2Long();
    long absAeDiff = lAeDiff * 10;	// 丸め誤差を解消するため10倍する		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
  	AeControlValue = absAeDiff;
    if (aeSpeed > 1) {	// aeSpeedが1の時余分に１足すので＿ZERO→_ONEに変更		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
      // 5-2-1 現フレーム目標変位量決定1 偏差×収束速度×10
      if (lAeDiff >= 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
        // 正数の場合は＋0.5
        AeControlValue = (absAeDiff + (aeSpeed >> 1)) / aeSpeed;		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
      } else {
        // 負数の場合はー0.5
        AeControlValue = (absAeDiff - (aeSpeed >> 1)) / aeSpeed;	// 右シフト見直しaeSpeed > 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
      }
    }

    // 5-2-2 現フレーム目標変位量決定2(非線形処理)
    if (OpdYAve >= lAeTarget) {
      // OPDYが目標値以上の場合
      AeControlValue = AeControlValue * NONLINEAR_COEFF_ONE;    //  係数1;  X100
    } else if (OpdYAve < lAeTargetQuarter) {
      // OPDYが目標値の1/4より小さい場合
      AeControlValue = AeControlValue * NONLINEAR_COEFF_THREE;  // 係数3; X100
    } else {
      // OPDYが目標値より小さく、目標値の1/4以上の場合
      AeControlValue = AeControlValue * NONLINEAR_COEFF_TWO;	// 係数2; X100
    }
    //1frame制御量　目標値に対する制御量の比率　（センサー出力が現在の制御量の結果とみなせるのでそれに対する増減分を計算する）
    LONG sensorOut = OpdYAve.conv2Long();		// 差分が負の時、異常に大きな値になるため ULONG → LONG修正
    AeControlValue = (AeControlValue * 100);	// sensorOutが０の場合1000倍されない ↑上記@@@1で10倍するようにしたので1000倍→100倍に修正		※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
  	if(sensorOut == 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
		sensorOut = 1;
  	}
  	if (sensorOut > 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
      if (AeControlValue >= 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
        AeControlValue = ((AeControlValue) + (sensorOut >> 1)) / sensorOut;	// 右シフト見直しsensorOut > 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
     //制御量が大きすぎないようにクリップ処理追加 Start
		if(AeControlValue > AECONTROLCLIP){
			AeControlValue = AECONTROLCLIP;
		}
     //制御量が大きすぎないようにクリップ処理追加 End
      } else {
        AeControlValue = ((AeControlValue) - (sensorOut >> 1)) / sensorOut;	// 右シフト見直しsensorOut > 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
     //制御量が大きすぎないようにクリップ処理追加 Start
		if(AeControlValue < -AECONTROLCLIP){
			AeControlValue = -AECONTROLCLIP;
		}
     //制御量が大きすぎないようにクリップ処理追加 End
      }
    }

  }  // end of if (ptrAeSettingRef != NULL)
//  for debug v v v
	setAEControlValue(AeControlValue);
//  for debug ^ ^ ^

}

void AXMIspAeBase::SelectControlObject(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "SelectControlObject" << endl;
  #endif
#endif
  if (ptrAeSettingRef != NULL) {
    AXMIspAeValue AeZeroValue;
    AeZeroValue.set(0, 0);		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

    switch (ptrAeSettingRef->AeMode) {
      //通常プログラムモード 開始
      case E_AeUsualProgMode:
      case E_AeUsualProg_MainObjMode:              			// 主要被写体 通常プログラムモード
      case E_AeUsualProg_HistogramMode:              		// ヒストグラム 通常プログラムモード
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "プログラム線図③" << endl;
  #endif
#endif
        ControlObject = selectSubr(
            ControlObject, 									// 制御種別　アイリス/シャッター/ゲイン/スローシャッター
        	getYLevelChangeDirection(),						// Yレベルの変更方向 Up/Down
            ptrAeSettingRef->objAeChara.SlowShutterEnable,	// スローシャッターの有効(true)/無効(false)
            true,											// 通常プログラムモードはアイリス有効(true)
            ptrAeSettingRef->objAeChara.PrioritySlowGain,	// スローシャッター(true)/ゲイン(false)の優先順位
	    	false );										// シャッター制御のみでない(false)
        break;
        //通常プログラムモード 終了
        //シャッター＆ゲイン制御AEモード 開始
      case E_AeShutterAndGainControlMode:
      case E_AeShutterControl_MainObjMode:         			// 主要被写体 シャッター制御モード
      case E_AeShutterControl_HistogramMode:         		// ヒストグラム シャッター制御モード
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "プログラム線図②" << endl;
  #endif
#endif
        ControlObject = selectSubr(
            ControlObject, 									// 制御種別　シャッター/ゲイン/スローシャッター
        	getYLevelChangeDirection(),						// Yレベルの変更方向 Up/Down
            ptrAeSettingRef->objAeChara.SlowShutterEnable, 	// スローシャッターの有効(true)/無効(false)
	    	false,											// シャッター＆ゲイン制御AEモードはアイリス無効(false)
            ptrAeSettingRef->objAeChara.PrioritySlowGain ,	// スローシャッター(true)/ゲイン(false)の優先順位
	    	false );										// シャッター制御のみでない(false)
        break;
        //シャッター＆ゲイン制御AEモード　終了
        //シャッター制御モード　開始
      case E_AeShutterControlMode:
      case E_AeShutterAndGainControl_MainObjMode:  			// 主要被写体 シャッター＆ゲイン制御AEモード
      case E_AeShutterAndGainControl_HistogramMode:  		// ヒストグラム シャッター＆ゲイン制御AEモード
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "プログラム線図①" << endl;
  #endif
#endif
        ControlObject = selectSubr(
            ControlObject, 									// 制御種別　シャッター/スローシャッター
        	getYLevelChangeDirection(),						// Yレベルの変更方向 Up/Down
            ptrAeSettingRef->objAeChara.SlowShutterEnable, 	// スローシャッターの有効(true)/無効(false)
	    	false,											// シャッター制御モードはアイリス無効(false)
      		true, 											//  シャッター制御時   PrioritySlowGain はスローシャッター優先(true)にする,
	    	true);											// シャッター制御のみ(true)
        break;
        //シャッター制御モード　終了
      default:
        break;
    }  // end of  switch (ptrAeSettingRef->AeMode)
  }  // end of if (ptrAeSettingRef != NULL)
}

void AXMIspAeBase::DecideControlValue(AXMIspAeControlExposure *controlExposure) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "DecideControlValue=";
  cout << ControlObject << endl;
  #endif
#endif
  controlExposure->doControlExposure = E_ISC_None;

  if (noChangeControl == false) {
    switch (ControlObject) {
      case CNTOBJ_SHUTSPED:  // 現シャッタースピード制御中
      default:
		controlExposure->doControlExposure = E_ISC_ShutterSpeed;
    	CalcExposureTime(controlExposure);
    	break;
      case CNTOBJ_GAIN:  // 現ゲイン制御中
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "gain control " << endl;
  #endif
#endif
		controlExposure->doControlExposure = E_ISC_Gain;
    	CalcImageSensorGain(controlExposure);
        break;
      case CNTOBJ_SLOWSHUT:  // 現スローシャッター制御中
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "slow shutter control " << endl;
  #endif
#endif
		controlExposure->doControlExposure = E_ISC_SlowShutter;
    	CalcExposureTime(controlExposure);
        break;
      case CNTOBJ_IRIS:  // 現アイリス制御中
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "iris control " << endl;
  #endif
#endif
#ifdef MECHA_IRIS
		controlExposure->doControlExposure = E_ISC_Iris;
    	JudgeIrisRegion(controlExposure , false);	// false is not WDR
#endif
        break;
    }
  }
	// モード切替後の数フレームはアイリスを開放する。
	forceIrisOpen(controlExposure);
}

void AXMIspAeBase::CalcLuminanceValue(AXMIspAeControlExposure *controlExposure , ST_FROM_AE_TO_ISP *execFromAeToIsp) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcLuminanceValue" << endl;
  #endif
#endif
	unsigned int shutter = controlExposure->contShutter;
	unsigned int gain = controlExposure->contGain;
#ifdef GAIN_TUNE
	if(gain > 600) {
		gain = 600;
	}
	unsigned int linearGain = cnvGainLinear[(gain+30)/60];
#else	// GAIN_TUNE
	if(gain > 60) {
		gain = 60;
	}
	unsigned int linearGain = cnvGainLinear[(gain+3)/6];
#endif	// GAIN_TUNE
	LONG luminance = Exposure1S;
	// 明るさデータ = 5/露光時間/ゲイン（リニア）
	luminance = luminance * 5;
	if(shutter > 1){
		luminance = (luminance + (shutter >> 1)) / shutter;	// Exposure1S / shutter シャッタースピードの逆数　1/60なら60	// 右シフト見直しshutter > 0 なので問題なし
	}
	if(linearGain > 1){
		luminance = (luminance + (linearGain >> 1)) / linearGain;	// 右シフト見直しlinearGain > 0 なので問題なし
	}
	if(luminance > 0x0000FFFF){
		luminance = 0x0000FFFF;
	}
	execFromAeToIsp->luminance = static_cast<unsigned short>(luminance);

// Day/Night
	if (ptrAeSettingRef != NULL) {
		if(ptrAeSettingRef->objDayNight.dayNightMode == DAYNIGHT_ON) {
			if(ptrAeSettingRef->objDayNight.forceMode == 0) {
				if(dayNightMode == DAYNIGHT_MODE_DAY) {
				// 現在Dayモード
					if(judgeDayNightInThreshold( &(ptrAeSettingRef->objDayNight))) {
					// Day→Night遷移閾値を超えている
						dayNightCount++;						// 判定時間カウントをカウントUP
						if(dayNightCount >= ptrAeSettingRef->objDayNight.judgeTransTime) {
						// 判定時間を経過した
							dayNightMode = DAYNIGHT_MODE_NIGHT;	// Nightモードに切替
						}
					} else {
					// 明るさがDay→Night遷移閾値内に戻った
						dayNightCount = 0;						// 判定時間カウントをリセット
					}
				} else {
				// 現在Nightモード
					if(judgeDayNightOutThreshold( &(ptrAeSettingRef->objDayNight))) {
					// Night→Day遷移閾値を超えているか？
						dayNightCount++;						// 判定時間カウントをカウントUP
						if(dayNightCount >= ptrAeSettingRef->objDayNight.judgeTransTime) {
						// 判定時間を経過した
							dayNightMode = DAYNIGHT_MODE_DAY;	// Dayモードに切替
						}
					} else {
						dayNightCount = 0;						// 判定時間カウントをリセット
					}
				} // end of if(dayNightMode == DAYNIGHT_MODE_DAY) 〜 else
			} else {
				if(ptrAeSettingRef->objDayNight.forceDayNightSelect == 0) {
					dayNightMode = DAYNIGHT_MODE_DAY;	// Dayモードに切替
				} else {
					dayNightMode = DAYNIGHT_MODE_NIGHT;	// Nightモードに切替
				}
			}
			if((ptrAeSettingRef->objDayNight.nightColorSig != 0) && (dayNightMode == DAYNIGHT_MODE_NIGHT)) {
				  controlExposure->chromaOff = 1;
			} else {
				  controlExposure->chromaOff = 0;

			}

		} // end of if(ptrAeSettingRef->objDayNight.dayNightMode == DAYNIGHT_ON)
		ptrAeSettingRef->objDayNight.dayNightIndicate = dayNightMode;
	} // end of if (ptrAeSettingRef != NULL)
}

void AXMIspAeBase::CalcExposureTime(AXMIspAeControlExposure *controlExposure) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcExposureTime" << endl;
  #endif
#endif
    	// イメージセンサ制御
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "beforeExposureTime (before)= ";
        cout << beforeExposureTime << endl;
  #endif
#endif
    beforeExposureTime = divBy10000(
        (beforeExposureTime * (10000L - AeControlValue))
            + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L, _TEN_THOUSAND -> 10000L）
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "AeControlValue = ";
        cout << AeControlValue << endl;
        cout << "beforeExposureTime (after)= ";
        cout << beforeExposureTime << endl;
  #endif
#endif
#ifdef IMX662
    shutterSpeed = divBy10000(
    	(beforeExposureTime * Exposure1PER60S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#elif IMX415	// IMX662
	// IMX415用
    shutterSpeed = divBy10000(
    	(beforeExposureTime * Exposure1PER30S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#else	// IMX662
	// IMX412用
    shutterSpeed = divBy10000(
    	(beforeExposureTime * Exposure1PER15S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#endif	// IMX662
	if(controlExposure->doControlExposure == E_ISC_ShutterSpeed){
		// シャッタースピードが範囲を超えた時のクリップ処理
		if(isShutterLowerLimit()){		// シャッタースピードが最小値を超える？
			shutterSpeed = shutterSpeedLower;	// シャッタースピード最小値にクリップする
			// 長時間動かすとAEが動かなくなる不具合に対応
		}

		if(isShutterUpperLimit()){		// シャッタースピードが最大値を超える？
			shutterSpeed = shutterSpeedUpper;	// シャッタースピード最大値にクリップする
		}
	}else /* if(controlExposure->doControlExposure == E_ISC_ShutterSpeed) */{
		// スローシャッタースピードが範囲を超えた時のクリップ処理
		if(isSlowShutterLowerLimit()){		// スローシャッタースピードが最小値を超える？
			shutterSpeed = slowShutterLower;	// スローシャッター最小値にクリップする
		}
		if(isSlowShutterUpperLimit()){		// スローシャッタースピードが最大値を超える？
			shutterSpeed = slowShutterUpper;	// スローシャッター最大値にクリップする
		}
	}
	// 暗くなる不具合に対応
#ifdef IMX662
	beforeExposureTime = ((shutterSpeed * 10000) + (Exposure1PER60S >> 1)) / Exposure1PER60S;	// 右シフト見直しExposure1PER60S > 0 なので問題なし
#elif IMX415	// IMX662
	// IMX415用
	beforeExposureTime = ((shutterSpeed * 10000) + (Exposure1PER30S >> 1)) / Exposure1PER30S;	// 右シフト見直しExposure1PER30S > 0 なので問題なし
#else	// IMX662
	// IMX412用
	beforeExposureTime = ((shutterSpeed * 10000) + (Exposure1PER15S >> 1)) / Exposure1PER15S;	// 右シフト見直しExposure1PER15S > 0 なので問題なし
#endif	// IMX662

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "shutterSpeed = ";
        cout << shutterSpeed << endl;
  #endif
#endif
        controlExposure->contShutter = shutterSpeed;
        controlExposure->contGain = gain;

}

void AXMIspAeBase::CalcImageSensorGain(AXMIspAeControlExposure *controlExposure) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcImageSensorGain" << endl;
  #endif
#endif
    	// イメージセンサ制御
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "beforeExposureGain (before)= ";
        cout << beforeExposureGain << endl;
  #endif
#endif
	//次回のゲイン＝現在のゲイン＋下記係数（＝7）×増減量
		LONG localControlValue = -(COEFF_GAIN_CHANGE * AeControlValue);	// AeControlValue が負の時にgainを増やすので符号を反転する
		if((localControlValue < 0) && (beforeExposureGain < static_cast<ULONG>(-localControlValue))){
			beforeExposureGain = 0;
		} else {
	        beforeExposureGain = (beforeExposureGain + localControlValue);
		}
#ifndef PARASOFT_CPPTEST 
  #ifndef COUT_DEBUG
        cout << "localControlValue = ";
        cout << localControlValue << endl;
        cout << "beforeExposureGain (after)= ";
        cout << beforeExposureGain << endl;
  #endif
#endif
#ifdef GAIN_TUNE
		// 前回ゲインが大きすぎると収束までに長時間かかるためクリップさせる
		// （完全に暗い状態から一気に明るくした際に長時間gainがマックスに張り付く問題対策）
		if (beforeExposureGain > (gainUpper * 1000)) {
			beforeExposureGain = (gainUpper * 1000);
		}
#else
		// 前回ゲインが大きすぎると収束までに長時間かかるためクリップさせる
		// （完全に暗い状態から一気に明るくした際に長時間gainがマックスに張り付く問題対策）
		if (beforeExposureGain > (gainUpper * 10000)) {
			beforeExposureGain = (gainUpper * 10000);
		}
#endif
		
        gain = gainLower + divBy10000(
#ifdef GAIN_TUNE
	       	(beforeExposureGain * 10) + 5000L);	// ドライバに少数第１位までを渡すために10倍する		※コンパイラ都合によりenumから数値に変更（_TEN -> 10, _FIVE_THOUSAND -> 5000L）
#else
        	(beforeExposureGain ) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#endif
		// ゲインの最小値超えチェックは、上記の「次回のゲイン」計算処理でガードされているので不要
		if(isGainUpperLimit()){		// ゲインが最大値を超える？
			gain = gainUpper;		// ゲインを最大値にクリップする
		}
		//Gainの最小値を０より大きくする場合があるのでクリップ必要
		if(isGainLowerLimit()){		// ゲインが最小値を超える？
			gain = gainLower;		// ゲインを最小値にクリップする
		}
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
        cout << "gain = ";
        cout << gain << endl;
  #endif
#endif
        controlExposure->contShutter = shutterSpeed;
        controlExposure->contGain = gain;

}

void AXMIspAeBase::CalcISPGain(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcISPGain" << endl;
  #endif
#endif
}

//#define DC_IRIS_DEBUG
#ifdef DC_IRIS_DEBUG
static USHORT iris_to_bright[256][32];
static USHORT iris_to_dark[256][32];
static UCHAR eval_state = 0;
static UCHAR control=0;
static USHORT irisValue = 0;
static LONG beforeOpdYAve = 0;
#endif

//#define P_IRIS_DEBUG
#ifdef P_IRIS_DEBUG
static LONG eval_state = 0;
static LONG control=0;
#endif

void AXMIspAeBase::ManageRoughIrisValue(AXMIspAeControlExposure *controlExposure) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "ManageRoughIrisValue" << endl;
  #endif
#endif
	if (ptrAeSettingRef != NULL) {
		if(controlExposure != NULL) {
			controlExposure->contShutter = ptrAeSettingRef->objAeManual.ShutterSpeed;		// シャッタースピード設定
			controlExposure->contGain    = ptrAeSettingRef->objAeManual.Gain;				// ゲイン設定
			controlExposure->doControlExposure = (E_ISC_ShutterSpeed|E_ISC_Gain);
			// 今回IRISは存在しないため不要
			/*
			controlExposure->contIris = IRIS_CONT_OPEN_FAST;
			controlExposure->doControlExposure |= E_ISC_Iris;
			*/
		}
		// 今回IRISは存在しないため不要
		/*
#ifdef DC_IRIS_DEBUG
		switch(eval_state){
		case 0:	// 暗くなるパターン準備
			//まずirisを全開にする。
        	controlExposure->contIris = 0;	//irisを早く開く
			controlExposure->doControlExposure |= E_ISC_Iris;
			if(beforeOpdYAve < OpdYAve.conv2Long()){
				control = 0;
			} else {
				control ++;
			}
			if(control >= 10){
				eval_state = 1;
				control=0;
			}
			break;
		case 1:	// 暗くなるパターン
        	controlExposure->contIris = irisValue;	//iris
			controlExposure->doControlExposure |= E_ISC_Iris;
			iris_to_dark[irisValue][control] = static_cast<USHORT>(OpdYAve.conv2Long());
			if(++control >= 32){
				eval_state = 0;
				control=0;
				if(++irisValue >= 256){
					eval_state = 2;
					irisValue = 0;
				}
			}
			break;
		case 2:	// 明るくなるパターン準備
			//まずirisを全閉にする。
        	controlExposure->contIris = 0xFF;	//irisを早く閉じる
			controlExposure->doControlExposure |= E_ISC_Iris;
			if(beforeOpdYAve > OpdYAve.conv2Long()){
				control = 0;
			} else {
				control ++;
			}
			if(control >= 10){	// 明るさが変わらない状態が１０回続けば次へ
				eval_state = 3;
				control=0;
			}
			break;
		case 3:	// 明るくなるパターン
        	controlExposure->contIris = irisValue;	//iris
			controlExposure->doControlExposure |= E_ISC_Iris;
			iris_to_bright[irisValue][control] = static_cast<USHORT>(OpdYAve.conv2Long());
			if(++control >= 32){
				eval_state = 2;
				control=0;
				if(++irisValue >= 256){
					eval_state = 4;
					irisValue = 0;
				}
			}
			break;
		default:
        	controlExposure->contIris = 0x00;	//irisを
			controlExposure->doControlExposure |= E_ISC_Iris;
			break;
		}
		beforeOpdYAve = OpdYAve.conv2Long();
#elif defined(P_IRIS_DEBUG)
  //  for debug v v v
		switch(control >> 7){	// 右シフト見直しcontrol >= 0 なので問題なし
		case 0:
			controlExposure->contIris = IRIS_CONT_OPEN_FAST;              // ⑤ 高速開動作
			break;
		case 1:
			controlExposure->contIris = IRIS_CONT_CLOSE_FAST;             // ③ 高速閉動作
			break;
		case 2:
			controlExposure->contIris = IRIS_CONT_OPEN_SLOW;              // ④ 低速開動作
			break;
		case 3:
			controlExposure->contIris = IRIS_CONT_CLOSE_SLOW;              // ⑤ 高速開動作
			break;
		default:
			controlExposure->contIris = IRIS_CONT_STOP;                   // ① 停止
			control = -1;
			break;
		}
		controlExposure->doControlExposure |= E_ISC_Iris;

	  	setAECalcData1(OpdYAve.conv2Long());
	  	setAECalcData2(eval_state);
		if((control >> 7) != ((control + 1) >> 7)){	// 右シフト見直しcontrol >= 0 なので問題なし
			eval_state++;
		}
		control++;
  //  for debug ^ ^ ^

#else
		if(ptrAeSettingRef->objAeMechaIris.FlagIrisRegion == 1){
			if(controlExposure != NULL) {
				controlExposure->contIris = ptrAeSettingRef->objAeMechaIris.RoughIrisValue;
				controlExposure->doControlExposure |= E_ISC_Iris;
			}
		}
		if((ptrAeSettingRef->objAeMechaIris.FlagIrisRegion >= 2) && (ptrAeSettingRef->objAeMechaIris.FlagIrisRegion <= 5)){
			if(controlExposure != NULL) {
				if(ptrAeSettingRef->objAeMechaIris.RoughIrisValue > 0) {
					switch(ptrAeSettingRef->objAeMechaIris.FlagIrisRegion) {
					case 2:
						controlExposure->contFocus = AF_CONT_TOINF_SLOW;
						break;
					case 3:
						controlExposure->contFocus = AF_CONT_TOMACRO_SLOW;
						break;
					case 4:
						controlExposure->contFocus = AF_CONT_TOINF_FAST;
						break;
					case 5:
						controlExposure->contFocus = AF_CONT_TOMACRO_FAST;
						break;
					}
					ptrAeSettingRef->objAeMechaIris.RoughIrisValue--;
				}else {
					controlExposure->contFocus = AF_CONT_STOP;
				}
				controlExposure->doControlExposure |= E_ISC_Focus;
				controlExposure->contIris = IRIS_CONT_STOP;
				controlExposure->doControlExposure |= E_ISC_Iris;
			}
		}
		if(ptrAeSettingRef->objAeMechaIris.FlagIrisRegion == 6){
			if(controlExposure != NULL) {
				controlExposure->contFocus = ptrAeSettingRef->objAeMechaIris.RoughIrisValue;
				controlExposure->doControlExposure |= E_ISC_Zoom;
				controlExposure->contIris = IRIS_CONT_STOP;
				controlExposure->doControlExposure |= E_ISC_Iris;
			}
		}
		if((ptrAeSettingRef->objAeMechaIris.FlagIrisRegion >= 7) && (ptrAeSettingRef->objAeMechaIris.FlagIrisRegion <= 10)){
			if(controlExposure != NULL) {
				if(ptrAeSettingRef->objAeMechaIris.RoughIrisValue > 0) {
					controlExposure->contFocus = ZOOM_CONT_ZOOMOUT_SLOW;
					switch(ptrAeSettingRef->objAeMechaIris.FlagIrisRegion) {
					case 7:
						controlExposure->contFocus = ZOOM_CONT_ZOOMOUT_SLOW;
						break;
					case 8:
						controlExposure->contFocus = ZOOM_CONT_ZOOMIN_SLOW;
						break;
					case 9:
						controlExposure->contFocus = ZOOM_CONT_ZOOMOUT_FAST;
						break;
					case 10:
						controlExposure->contFocus = ZOOM_CONT_ZOOMIN_FAST;
						break;
					}
					ptrAeSettingRef->objAeMechaIris.RoughIrisValue--;
				}else {
					controlExposure->contFocus = ZOOM_CONT_STOP;
				}
				controlExposure->doControlExposure |= E_ISC_Zoom;
				controlExposure->contIris = IRIS_CONT_STOP;
				controlExposure->doControlExposure |= E_ISC_Iris;
			}
		}
#endif
		*/
	}
}

#ifdef MECHA_IRIS
void AXMIspAeBase::JudgeIrisRegion(AXMIspAeControlExposure *controlExposure, bool isWdrMode) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "JudgeIrisRegion" << endl;
  #endif
#endif
	
	// 変化指数 Idif＝（現在の偏差前フレームの偏差）／現在の偏差
	// AeDiffFrameNo は AeDiffLog[]に「現在の偏差」を格納したあと次の格納位置を指している。
	// したがって
	// 「現在の偏差」格納位置  = (AeDiffFrameNo + 3) & 3;
	// 「前フレームの偏差」格納位置  = (AeDiffFrameNo + 2) & 3;
	// となる。
	SHORT currentAeDiffFrameNo = (st_AeDiff[AE_USUAL_BANK].AeDiffFrameNo + 3) & 3;	// 「現在の偏差」格納位置
	SHORT beforeAeDiffFrameNo  = (st_AeDiff[AE_USUAL_BANK].AeDiffFrameNo + 2) & 3;	// 「前フレームの偏差」格納位置
	LONG currentAeDiff = st_AeDiff[AE_USUAL_BANK].AeDiffLog[currentAeDiffFrameNo].conv2Long();	// ×10
	LONG beforeAeDiff  = st_AeDiff[AE_USUAL_BANK].AeDiffLog[beforeAeDiffFrameNo].conv2Long();	// ×10
	LONG Idif = (currentAeDiff - beforeAeDiff)*1000;
	LONG absIdif = Idif;

#ifdef PARASOFT_CPPTEST
	setIrisValueFrame(currentAeDiffFrameNo , beforeAeDiffFrameNo);
	setIrisValueDiff(currentAeDiff , beforeAeDiff);
#endif

	if(absIdif < 0){
		absIdif = -absIdif;
	}
	if(currentAeDiff == 0){
		absIdif = 0;
	} else {
		LONG absCurrentAeDiff = currentAeDiff;
		if(absCurrentAeDiff < 0){
			absCurrentAeDiff = -absCurrentAeDiff;
		}
		absIdif = ((absIdif * 10) + (absCurrentAeDiff >> 1)) / absCurrentAeDiff;	// 右シフト見直しabsCurrentAeDiff >= 0 なので問題なし
	}
#ifdef PARASOFT_CPPTEST
	setIrisValueAbsDiff(absIdif);
#endif

	// ２種類の閾値を求める
	//   1.停止と低速動作の閾値 Th1
	//   2.低速動作と高速動作の閾値 Th2

	// Th1は固定値部分とTh1fと変化指数で変更される可変部分Th1vがある。
	// Th1＝Th1f＋Th1v
	// Th1vは変化指数に反映係数Cdifを掛けたものである。
	// Th1v＝Idif×Cdif
	// アイリス閉時はIRIS_THR_TH1F_IN、アイリス開時はIRIS_THR_TH1F_OUT
	LONG Th1 = (currentAeDiff >= 0) ? IRIS_THR_TH1F_IN : IRIS_THR_TH1F_OUT;
	Th1 += ((absIdif * IRIS_THR_CDIF)+5000)/10000;	// Th1f は 10000倍された係数 	// Cdif は 10000倍された係数
	// Th2は固定値であるが、その絶対値はTh1より小さくならないようにする。
	// Th2の与えられる固定値をTh2fとすると以下のようになる。
	// ｜Th2｜＝MAX（｜Th2f｜，｜Th1｜）
	LONG absTh1 = (Th1 < 0) ? (-Th1) : Th1;	// ｜Th1｜を求める
	LONG absTh2f = (IRIS_THR_TH2F < 0) ? (-IRIS_THR_TH2F) : IRIS_THR_TH2F;	// ｜Th2f｜を求める // Th2f は 10000倍された係数
	LONG absTh2 = (absTh2f >= absTh1) ? absTh2f : absTh1;
	
	// 動作としては以下のようになる。
	// ① -Th1≦増減量≦Th1  ⇒ 停止
	// ② Th1＜増減量≦Th2   ⇒ 低速閉動作
	// ③ Th2＜増減量        ⇒ 高速閉動作
	// ④ -Th2≦増減量＜-Th1 ⇒ 低速開動作
	// ⑤ 増減量＜-Th2       ⇒ 高速開動作
	bool isIrisOpen = false;
	if(irisCntl == irisUpper) {			// シャッター制御に遷移する時は、アイリスを停止させる
		controlExposure->contIris = IRIS_CONT_STOP;                   // ① 停止
	}else if((-absTh1 <= AeControlValue) && (AeControlValue <= absTh1)){
		controlExposure->contIris = IRIS_CONT_STOP;                   // ① 停止
	}else if((absTh1 < AeControlValue) && (AeControlValue <= absTh2)){
		controlExposure->contIris = IRIS_CONT_CLOSE_SLOW;             // ② 低速閉動作
	}else if(absTh2 < AeControlValue){
		controlExposure->contIris = IRIS_CONT_CLOSE_FAST;             // ③ 高速閉動作
	}else if((-absTh2 <= AeControlValue) && (AeControlValue < -absTh1)){
		controlExposure->contIris = IRIS_CONT_OPEN_SLOW;              // ④ 低速開動作
		isIrisOpen = true;
	}else{ // if(AeControlValue < -absTh2)
		controlExposure->contIris = IRIS_CONT_OPEN_FAST;              // ⑤ 高速開動作
		isIrisOpen = true;
	}

	if((Idif >= 0) && (Idif < 1000) && (isIrisOpen)){	// Idif は1000倍しているため1000より小さ、及び０以上ならば変化無しとする
		irisNoChangeFrameCnt ++;
		UCHAR irisNoChangeTimes = (isWdrMode) ? IRIS_NO_CHANGE_TIMES_WDR : IRIS_NO_CHANGE_TIMES;
		if(irisNoChangeFrameCnt >= irisNoChangeTimes){
			irisCntl = irisUpper;							// シャッター制御に遷移する
			controlExposure->contIris = IRIS_CONT_STOP;                   // ① 停止
		}
	} else {
		irisNoChangeFrameCnt = 0;
	}

#ifdef PARASOFT_CPPTEST
	setIrisValue(absTh1 , absTh2);
#endif
//  for debug v v v
	setIrisThValue(absTh1 , absTh2 , irisNoChangeFrameCnt);
//  for debug ^ ^ ^

}
#endif

ULONG AXMIspAeBase::divBy10000(ULONG dividend) {
  ULONG quotient = 0;
  while (dividend >= 100000000L) {  // １億以上の場合		※コンパイラ都合によりenumから数値に変更（_HUNDRED_MILLION -> 100000000L）
    quotient += 10000L;  //　10000の位をUp		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
    dividend -= 100000000L;  // 1億減算		※コンパイラ都合によりenumから数値に変更（_HUNDRED_MILLION -> 100000000L）
  }
  while (dividend >= 10000000L) {      // 1千万以上の場合		※コンパイラ都合によりenumから数値に変更（_TEN_MILLION -> 10000000L）
    quotient += 1000L;      //　1000の位をUp		※コンパイラ都合によりenumから数値に変更（_THOUSAND -> 1000L）
    dividend -= 10000000L;      // 1千万減算		※コンパイラ都合によりenumから数値に変更（_TEN_MILLION -> 10000000L）
  }
  while (dividend >= 1000000L) {          // 100万以上の場合		※コンパイラ都合によりenumから数値に変更（_MILLION -> 1000000L）
    quotient += 100;          //　100の位をUp		※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
    dividend -= 1000000L;          // 百万減算		※コンパイラ都合によりenumから数値に変更（_MILLION -> 1000000L）
  }
  while (dividend >= 100000L) {  // 10万以上の場合		※コンパイラ都合によりenumから数値に変更（_HUNDRED_THOUSAND -> 100000L）
    quotient += 10;  //　10の位をUp		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
    dividend -= 100000L;  // 十万減算		※コンパイラ都合によりenumから数値に変更（_HUNDRED_THOUSAND -> 100000L）
  }
  while (dividend >= 10000L) {     // 1万以上の場合		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
    quotient += 1;     //　1の位をUp		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
    dividend -= 10000L;     // 一万減算		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
  }
  return quotient;
}

AXMispAeWeightOPD::AXMispAeWeightOPD() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  TAG = "AXMispAeWeightOPD::";
  cout << TAG + "constructor" << endl;
  #endif
#endif
  for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    OpdY[i] = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    OpdYWeighted[i] = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  }
  addCounter = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
}

AXMispAeWeightOPD::~AXMispAeWeightOPD() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMispAeWeightOPD::WeightOPD(const UCHAR array[]) {
  if (array != NULL) {
    for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
      OpdY[i] = array[(i * 4) + 3];		// ※コンパイラ都合によりenumから数値に変更（_THREE -> 3, _FOUR -> 4）
    }
  }
  AXMIspPhotometModes PhotometryPatternNo = E_PhotometCenter;
  UCHAR *p_Weight;		// klockwork 指摘に対応
  if (ptrAeSettingRef != NULL) {
    PhotometryPatternNo = ptrAeSettingRef->objAeChara.PhotometryPatternNo;
  }
  switch (PhotometryPatternNo) {
    case E_PhotometCenter:		// 中央重点
    default:
      p_Weight = const_cast<UCHAR *>(PhotometPre1);
      break;
    case E_PhotometUnderCent:		// 中央下重点
      p_Weight = const_cast<UCHAR *>(PhotometPre2);
      break;
    case E_PhotometRight:		// 右重点
      p_Weight = const_cast<UCHAR *>(PhotometPre3);
      break;
    case E_PhotometLeft:		// 左重点
      p_Weight = const_cast<UCHAR *>(PhotometPre4);
      break;
    case E_PhotometUser:		// ユーザー指定重点
      p_Weight = const_cast<UCHAR *>(ptrAeSettingRef->objAePhotPatt.PhotometUSER);
      break;
  };

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "WeightOPD" << endl;
  #endif
#endif
  addCounter = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    OpdYWeighted[i] = OpdY[i] * p_Weight[i];
    addCounter += p_Weight[i];
  }

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << "OpdY:" << endl;
  #endif
  for (USHORT row = 0; row < PHOTOMET_ROW; row++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    for (USHORT col = 0; col < PHOTOMET_COLUMN; col++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  #ifndef COUT_DEBUG
      cout << std::setw(4);		// ※コンパイラ都合によりenumから数値に変更（_FOUR -> 4）
      cout << dec << (USHORT) OpdY[row * PHOTOMET_COLUMN + col];
      cout << " , ";
  #endif
    }
  #ifndef COUT_DEBUG
    cout << endl;
  #endif
  }
  #ifndef COUT_DEBUG
  cout << "p_Weight:" << endl;
  #endif
  for (USHORT row = 0; row < PHOTOMET_ROW; row++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    for (USHORT col = 0; col < PHOTOMET_COLUMN; col++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  #ifndef COUT_DEBUG
      cout << setw(4);		// ※コンパイラ都合によりenumから数値に変更（_FOUR -> 4）
      cout << dec << (USHORT) p_Weight[row * PHOTOMET_COLUMN + col];
      cout << " , ";
  #endif
    }
  #ifndef COUT_DEBUG
    cout << endl;
  #endif
  }
  #ifndef COUT_DEBUG
  cout << "OpdYWeighted:" << endl;
  #endif
  for (USHORT row = 0; row < PHOTOMET_ROW; row++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    for (USHORT col = 0; col < PHOTOMET_COLUMN; col++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  #ifndef COUT_DEBUG
      cout << setw(4);		/ / ※コンパイラ都合によりenumから数値に変更（_FOUR -> 4）
      cout << dec << OpdYWeighted[row * PHOTOMET_COLUMN + col];
      cout << " , ";
  #endif
    }
  #ifndef COUT_DEBUG
    cout << endl;
  #endif
  }
#endif
	// LISRに設定が無いため不要
	/*
	  //  for debug v v v
  	setAEMainObj(GetReg32(RegSPU_DMAW0_OFS) , GetReg32(RegSPU_DMAW1_OFS) , (unsigned int)array);
		setRegLog(GetReg32(RegSPU_C) , GetReg32(RegMIX_ACT));
	  //  for debug ^ ^ ^
	*/

}

void AXMispAeWeightOPD::CalcAverageOPD() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAverageOPD" << endl;
  #endif
#endif
  USHORT addition = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  USHORT i;
  for (i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    addition += OpdYWeighted[i];
  }
// 平均
  if (addCounter > 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    OpdYAve = static_cast<long>(((addition * 10)		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
        + ((addCounter + 1) >> 1)) / addCounter);  // 少数第２位を四捨五入	// 右シフト見直し(addCounter + _ONE) >= 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
  }

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << setw(4);		// ※コンパイラ都合によりenumから数値に変更（_FOUR -> 4）
  cout << "addition=";
  cout << dec << addition << endl;
  cout << "addCounter=";
  cout << dec << (USHORT) addCounter << endl;

  cout << "OpdYAve =";
  OpdYAve.print();
  #endif
#endif
  //  for debug
  	setAECalcData1(OpdYAve.conv2Long());
  //  for debug

}

AXMIspAeHistogramBase::AXMIspAeHistogramBase() {
#ifndef COUT_DEBUG
  TAG = "AXMIspAeAutoBLFLCHistogram::";
  cout << TAG + "constructor" << endl;
#endif
	for(SHORT i = 0; i < HISTMAX ; i++ ) {
		Histogram[i] = initHistStruct;
	}

  
  OpdYLowLumiAreaAve = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYHighLumiAreaAve = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  NonMainObjectAreaWeight = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  histDivPoint = 0;					// 分割ポイント		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  histDivFrequency = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYAllTotal = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYAllCount = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  histDivLogNo = 0;	// histDivLogNo:0〜3
  histDivLogFlag = 0;
  for(int i = 0 ; i < HIST_DIV_LOG_MAX ; i++) {
	histDivLog[i] = 0;
  }
  w_aveLogNo = 0;
  w_aveLogFlag = 0;
  for(int i = 0 ; i < W_AVE_LOG_MAX ; i++) {
	w_aveLog[i] = 0;
  }

}

AXMIspAeHistogramBase::~AXMIspAeHistogramBase() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMIspAeHistogramBase::CalcHistogram(const UCHAR array[]) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcHistogram" << endl;
  #endif
#endif
	initHistogram();
	if (array != NULL) {
		for (SHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
			setHistogramSect(array[(i * 4) + 3]);	// ※コンパイラ都合によりenumから数値に変更（_THREE -> 3, _FOUR -> 4）
		}
	}
}

void AXMIspAeHistogramBase::initHistogram(void) {
	for(SHORT i = 0; i < HISTMAX ; i++ ) {
		Histogram[i] = initHistStruct;
	}
	
  OpdYLowLumiAreaAve = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYHighLumiAreaAve = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  NonMainObjectAreaWeight = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  histDivPoint = 0;					// 分割ポイント		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  histDivFrequency = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYAllTotal = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYAllCount = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
}

void AXMIspAeHistogramBase::setHistogramSect(UCHAR Ylevel) {
	for (SHORT bin = 0; bin < HISTMAX; bin++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
		if((histSect[bin].lower <= Ylevel) && (Ylevel <= histSect[bin].upper)) {
			Histogram[bin].frequency ++;
			Histogram[bin].weighted += histSect[bin].weight;	// weighted ← 度数×重み付け
		}
	}
}

SHORT AXMIspAeHistogramBase::getHistogramValue(UCHAR Ylevel) {
	SHORT bin;
	bool skipFreqZero = 0;
	bool findTarget = 0;
	for ( bin = 0; bin < HISTMAX; bin++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
		if(Histogram[bin].frequency > 0) {
			skipFreqZero = true;	// 度数0を飛ばす
			if(findTarget) {
				break;
			}
		}
		if((histSect[bin].center <= Ylevel) && (Ylevel <= histSect[bin].upper)) {
			findTarget = true;	// 目標値のbinが見つかった
			if(skipFreqZero) {
				break;			//ここまでの度数が0なら探索続行
			}
		}
	}
	return bin;
}


void AXMIspAeHistogramBase::DivHistogram(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "DivHistogram" << endl;
  #endif
#endif
		SHORT bin;

#if 1
	SHORT weight = Histogram[0].weighted;
	EVAL_PEAK_VALLEY pv_flag = EVAL_FLAT;
	

	for ( bin = 0; bin < HISTMAX; bin++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	// 重み付け度数の山谷を探す

		if(Histogram[bin].weighted > weight) {
			pv_flag = EVAL_UPPER;						// 前の重みより大きくなれば上昇 度数の差が2以上
			weight = Histogram[bin].weighted;
		} else if (Histogram[bin].weighted < weight) {
			pv_flag = EVAL_LOWER;						// 前の重みより小さくなれば下降 度数の差が2以上
			weight = Histogram[bin].weighted;
		} else {										// 重みに変化なし
			if(pv_flag == EVAL_UPPER){
				pv_flag = EVAL_FLAT_AFTER_UPPER;		// 上昇の後の平坦
			} else if(pv_flag == EVAL_LOWER){
				pv_flag = EVAL_FLAT_AFTER_LOWER;		// 下降の後の平坦
			}
		}
		Histogram[bin].eval = pv_flag;
	}

	pv_flag = EVAL_FLAT;
	for ( bin = HISTMAX; bin > 0 ; bin--) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
		switch(Histogram[bin-1].eval){
		case EVAL_UPPER:				// 上昇
			if(pv_flag == EVAL_LOWER){
				Histogram[bin-1].pv_flag = HIST_PEAK;
			}
			pv_flag = EVAL_UPPER;
			break;
		case EVAL_FLAT_AFTER_UPPER: 	// 上昇の後の平ら
			if(pv_flag == EVAL_LOWER){
				Histogram[bin-1].pv_flag = HIST_PEAK;
			}
			break;
		case EVAL_LOWER:				// 下降
			if(pv_flag == EVAL_UPPER){
				Histogram[bin-1].pv_flag = HIST_VALLEY;
			}
			pv_flag = EVAL_LOWER;
			break;
		case EVAL_FLAT_AFTER_LOWER:		// 下降の後の平ら
			if(pv_flag == EVAL_UPPER){
				Histogram[bin-1].pv_flag = HIST_VALLEY;
			}
			break;
		default:
			break;
		}
	}
#endif

	SHORT lowestFrequency = 0;
	SHORT lowestWeight = 0x7FFF;
	SHORT lowestBin =  19;
// 目標値が大きい時ハンチングする不具合に対応 Start
	LONG  locAeTarget = 255;

		locAeTarget = AeTarget.conv2Long();

	if(locAeTarget >= 800 /*|| SelectBL_CorFLC == 0*/) {
		bin = 0;
	} else {
		bin = HIST_DIV_POINT_START;
	}
// 目標値が大きい時ハンチングする不具合に対応 End
	for ( ; bin <= HIST_DIV_POINT_END ; bin++ ) {	// HIST_DIV_POINT_START , HIST_DIV_POINT_ENDは-1されている
		SHORT frequency = Histogram[bin].frequency;
		if((Histogram[bin].pv_flag == HIST_VALLEY) && (Histogram[bin].weighted < lowestWeight))
		{
			//ハンチング対応
			lowestWeight = Histogram[bin].weighted;
			lowestFrequency = frequency;
			lowestBin = bin;
		}
	}
	if(lowestBin < 19 /*&& (peakFreqRight - lowestFrequency) >= 1 && (peakFreqLeft - lowestFrequency) >= 1*/ ) {
		histDivPoint = histSect[lowestBin].center;	// 分割ポイント←最小評価値のbinの中心値
		lowestFrequency = Histogram[lowestBin].frequency;
	}
#if 1
	else{
		UCHAR ylevel = (UCHAR)((locAeTarget + 5) / 10);
		lowestBin = getHistogramValue(ylevel);
		if(lowestBin < 18) {
			histDivPoint = histSect[lowestBin].center;	// 分割ポイント←最小評価値のbinの中心値
			lowestFrequency = Histogram[lowestBin].frequency;
		}
	}
#endif
	histDivFrequency = lowestFrequency;
	
// for debug v v v
	for ( bin = 0; bin < HISTMAX ; bin++ ) {
		setHistogramLog(bin , Histogram[bin].weighted);
		setHistogramLog2(bin , (Histogram[bin].pv_flag << 8)  | (Histogram[bin].eval));
	}
	setHistogramLog2(bin , histDivFrequency);

// for debug ^ ^ ^

}

void AXMIspAeHistogramBase::CalcAverageLowLumiAreaOPD(const UCHAR array[]) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAverageLowLumiAreaOPD" << endl;
  #endif
#endif
  OpdYLowLumiAreaAve = 0;
  SHORT opdYLowLumiCount = 0;
  SHORT opdYLowLumiTotal = 0;

  if (array != NULL) {
    for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    	UCHAR opdY = array[(i * 4) + 3];		// ※コンパイラ都合によりenumから数値に変更（_THREE -> 3, _FOUR -> 4）
    	if(opdY <= histDivPoint){
    		opdYLowLumiCount ++;
			opdYLowLumiTotal += opdY;
    	}
    }
  	OpdYAllTotal += opdYLowLumiTotal;
  	OpdYAllCount += opdYLowLumiCount;
  	OpdYLowLumiAreaAve = opdYLowLumiTotal;
  	if(opdYLowLumiCount > 1){		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
  		OpdYLowLumiAreaAve = (OpdYLowLumiAreaAve + (opdYLowLumiCount >> 1)) / opdYLowLumiCount;	// 右シフト見直しmainObjectAreaCount >= 0 なので問題なし
  	}
  	if(OpdYLowLumiAreaAve == 0) {
		OpdYLowLumiAreaAve = histDivPoint;
  	}
  }
}

void AXMIspAeHistogramBase::CalcAverageHighLumiAreaOPD(const UCHAR array[]) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
	cout << TAG + "CalcAverageHighLumiAreaOPD" << endl;
  #endif
#endif
  OpdYHighLumiAreaAve = 0;
  SHORT opdYHighLumiCount = 0;
  SHORT opdYHighLumiTotal = 0;

  if (array != NULL) {
    for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    	UCHAR opdY = array[(i * 4) + 3];		// ※コンパイラ都合によりenumから数値に変更（_THREE -> 3, _FOUR -> 4）
    	if(opdY >= histDivPoint){
    		opdYHighLumiCount ++;
			opdYHighLumiTotal += opdY;
    	}
    }
  	OpdYAllTotal += opdYHighLumiTotal;
  	OpdYAllCount += opdYHighLumiCount;

  	OpdYHighLumiAreaAve = opdYHighLumiTotal;
  	if(opdYHighLumiCount > 1){		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
  		OpdYHighLumiAreaAve = (OpdYHighLumiAreaAve + (opdYHighLumiCount >> 1)) / opdYHighLumiCount;	// 右シフト見直しmainObjectAreaCount >= 0 なので問題なし
  	}
  	if(OpdYHighLumiAreaAve == 0) {
		OpdYHighLumiAreaAve = histDivPoint;
  	}
  }
}

AXMIspAeAutoBLFLCHistogram::AXMIspAeAutoBLFLCHistogram() {
#ifndef COUT_DEBUG
  TAG = "AXMIspAeAutoBLFLCHistogram::";
  cout << TAG + "constructor" << endl;
#endif
	SelectBL_CorFLC = 0;
}

AXMIspAeAutoBLFLCHistogram::~AXMIspAeAutoBLFLCHistogram() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMIspAeAutoBLFLCHistogram::CalcAverageALLHist(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAverageALLHist" << endl;
  #endif
#endif
	SHORT AllCount = OpdYAllCount;
	SHORT MainLv = 0;
	SHORT AllLv = OpdYAllTotal;

	if(AllCount > 1) {
		AllLv = (OpdYAllTotal + (AllCount >> 1)) / AllCount;
	}
  if (ptrAeSettingRef != NULL) {
	SelectBL_CorFLC = ptrAeSettingRef->objAeChara.SelectBL_CorFLC;
  }

	// 明確な暗部と明部に分かれていない場合はMainLvを0のままにし平均測光でAE評価値を生成する。
	if(histDivFrequency <= HIST_SUIT_THRESH) {
		MainLv = (SelectBL_CorFLC == 0) ? OpdYLowLumiAreaAve : OpdYHighLumiAreaAve;
	}
	LONG w_ave = (((HIST_CORRECT_STRENGTH * MainLv) + AllLv) * 10);		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
	if(MainLv > 0) {
		w_ave = (w_ave + ((HIST_CORRECT_STRENGTH + 1) >> 1)) / (HIST_CORRECT_STRENGTH + 1);
	}
#if 1
	// 安定化処理 Start
	if(w_aveLogFlag == 0) {
		for( SHORT i = 0; i < W_AVE_LOG_MAX ; i++ ) {
			w_aveLog[i] = w_ave;
		}
		w_aveLogFlag = 1;
	}
    w_aveLog[w_aveLogNo] = w_ave;
    w_aveLogNo = (w_aveLogNo + 1) & (W_AVE_LOG_MAX-1);	// w_aveLogNo:0〜7		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
	LONG w_aveLogTotal = 0;
	for( SHORT i = 0; i < W_AVE_LOG_MAX ; i++ ) {
		w_aveLogTotal += w_aveLog[i];
	}
	OpdYAve = (w_aveLogTotal + (W_AVE_LOG_MAX/2))/ W_AVE_LOG_MAX;
	// 安定化処理 End
#else

	OpdYAve = w_ave;
#endif	
  //  for debug v v v
  	setAECalcData1(OpdYAve.conv2Long());
  	setAEMainObj(MainLv , AllLv , histDivPoint | (SelectBL_CorFLC << 16));
	setRegLog(OpdYLowLumiAreaAve, OpdYHighLumiAreaAve);
  //  for debug ^ ^ ^

}

AXMIspAEAutoBLFLCMainObject::AXMIspAEAutoBLFLCMainObject() {
  OpdYNonMainObjectAve = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  OpdYMainObjectAve = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  NonMainObjectAreaWeight = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
}

AXMIspAEAutoBLFLCMainObject::~AXMIspAEAutoBLFLCMainObject() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMIspAEAutoBLFLCMainObject::CalcAverageMainObjectOPD(const UCHAR array[]) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAverageMainObjectOPD" << endl;
  #endif
#endif
	UCHAR *mainObjectAreaInfo = NULL;
	
	if (ptrAeSettingRef != NULL) {
		mainObjectAreaInfo = &ptrAeSettingRef->objAeChara.AXMIspAeMainObjectAreaInfo[0];
	}
  OpdYMainObjectAve = 0;	// MainLvを求める
  LONG mainObjectAreaCount = 0;
  LONG mainObjectAreaTotal = 0;

  if (array != NULL && mainObjectAreaInfo != NULL) {
    for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    	if(mainObjectAreaInfo[i] != 0){		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    		mainObjectAreaCount ++;
			mainObjectAreaTotal += array[(i * 4) + 3] ;		// ※コンパイラ都合によりenumから数値に変更（_THREE -> 3, _FOUR -> 4）
    	}
    }
  	OpdYMainObjectAve = mainObjectAreaTotal;
  	if(mainObjectAreaCount > 1){		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
  		OpdYMainObjectAve = (OpdYMainObjectAve + (mainObjectAreaCount >> 1)) / mainObjectAreaCount;	// 右シフト見直しmainObjectAreaCount >= 0 なので問題なし
  	}
  }
}

void AXMIspAEAutoBLFLCMainObject::CalcAverageNonMainObjectOPD(const UCHAR array[]) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAverageNonMainObjectOPDAXMIspAeAlgorithm" << endl;
  #endif
#endif

	UCHAR *mainObjectAreaInfo = NULL;
	
	if (ptrAeSettingRef != NULL) {
		mainObjectAreaInfo = &ptrAeSettingRef->objAeChara.AXMIspAeMainObjectAreaInfo[0];
	}
	OpdYNonMainObjectAve = 0;	// MainLvを求める
  LONG nonMainObjectAreaCount = 0;
  LONG nonMainObjectAreaTotal = 0;

  if (array != NULL && mainObjectAreaInfo != NULL) {
    for (USHORT i = 0; i < PHOTOMET_MAX; i++) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    	if(mainObjectAreaInfo[i] == 0){		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    		nonMainObjectAreaCount ++;
			nonMainObjectAreaTotal += array[(i * 4) + 3] ;		// ※コンパイラ都合によりenumから数値に変更（_THREE -> 3, _FOUR -> 4）
    	}
    }
    OpdYNonMainObjectAve = nonMainObjectAreaTotal;
  	if(nonMainObjectAreaCount > 1){		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
  		OpdYNonMainObjectAve = (OpdYNonMainObjectAve + (nonMainObjectAreaCount >> 1)) / nonMainObjectAreaCount;	// 右シフト見直しnonMainObjectAreaCount >= 0 なので問題なし
  	}
  }

}

void AXMIspAEAutoBLFLCMainObject::WeightNonMainObjectArea(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "WeightNonMainObjectArea" << endl;
  #endif
#endif
	// ① OtherLv ≧MainLv →逆光補正時
	//    Weight＝Ga（ゲイン）×OtherLv／MainLv＋Off（オフセット）
	// ② MainLv ＞OtherLv →過順光補正時
	//    Weight＝Ga（ゲイン）×MainLv ／OtherLv＋Off（オフセット）
	// MAIN_OBJECT_GAIN , MAIN_OBJECT_OFFSETは10倍された値
	if(OpdYNonMainObjectAve >= OpdYMainObjectAve) {	//左辺と右辺入れ替え
		NonMainObjectAreaWeight = (MAIN_OBJECT_GAIN * OpdYNonMainObjectAve);	// MAIN_OBJECT_GAINは１０倍された値
		if(OpdYMainObjectAve > 1){		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
			NonMainObjectAreaWeight = (NonMainObjectAreaWeight + (OpdYMainObjectAve >> 1)) / OpdYMainObjectAve;	// 右シフト見直しOpdYMainObjectAve >= 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
		}
		NonMainObjectAreaWeight += MAIN_OBJECT_OFFSET;
	} else {
		NonMainObjectAreaWeight = (MAIN_OBJECT_GAIN * OpdYMainObjectAve);
		if(OpdYNonMainObjectAve > 1) {		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
			NonMainObjectAreaWeight = (NonMainObjectAreaWeight + (OpdYNonMainObjectAve >> 1))/ OpdYNonMainObjectAve;	// 右シフト見直しOpdYNonMainObjectAve >= 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
		}
		NonMainObjectAreaWeight += MAIN_OBJECT_OFFSET;	// MAIN_OBJECT_OFFSETは１０倍された値
	}
}

void AXMIspAEAutoBLFLCMainObject::CalcAverageALL(void) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcAverageALL" << endl;
  #endif
#endif
	LONG w_ave = ((NonMainObjectAreaWeight * OpdYMainObjectAve) + (OpdYNonMainObjectAve * 10));		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
	// 重み付け平均 W-Ave=（Weight×MainLv＋OtherLv）／（Weight＋１）
	if((NonMainObjectAreaWeight + 1) > 1) {		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
		w_ave = ((w_ave * 10) + ((NonMainObjectAreaWeight + 1) >> 1)) / (NonMainObjectAreaWeight + 1);	// 右シフト見直しNonMainObjectAreaWeight >= 0 なので問題なし		※コンパイラ都合によりenumから数値に変更（_ONE -> 1, _TEN -> 10）
	}
	OpdYAve = w_ave;
  //  for debug v v v
  	setAECalcData1(OpdYAve.conv2Long());
  	setAEMainObj(OpdYMainObjectAve , OpdYNonMainObjectAve , NonMainObjectAreaWeight);
  //  for debug ^ ^ ^

}

YLVLDISPL AXMIspAeBase::getYLevelChangeDirection(void) {
  LONG aeValue = AeDiff.conv2Long();
  YLVLDISPL direct = YLVL_UNCHANGE;
  if (aeValue > 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    direct = YLVL_LOWER;	// 現在のＹレベル＞目標値なので下げ方向を返す
  } else if (aeValue < 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    direct = YLVL_UPPER;	// 現在のＹレベル＜目標値なので下げ方向を返す
  } else {
    direct = YLVL_UNCHANGE;  // 現在のＹレベル==目標値なので変位なしを返す
  }
  return direct;
}

CNTOBJ AXMIspAeBase::selectSubr(CNTOBJ currobj, YLVLDISPL dir, bool slowshut,
                                bool irisflag, bool priSlowGain, bool ssOnly) {
  CNTOBJ nextobj = currobj;
  outOfLimit = false;
  noChangeControl = false;
  switch (currobj) {
    case CNTOBJ_SHUTSPED:  // 現シャッタースピード制御中
  		nextobj = selectSubr_Shutter( currobj,  dir,  slowshut, irisflag,  priSlowGain,  ssOnly);
      break;
    case CNTOBJ_GAIN:		// 現ゲイン制御中
  		nextobj = selectSubr_Gain( currobj,  dir,  slowshut, irisflag,  priSlowGain,  ssOnly);
      break;
    case CNTOBJ_SLOWSHUT:  // 現低速シャッター制御中
  		nextobj = selectSubr_SlowShutter( currobj,  dir,  slowshut, irisflag,  priSlowGain,  ssOnly);
		break;
  	case CNTOBJ_IRIS:		// 現アイリス制御中
  		nextobj = selectSubr_Iris( currobj,  dir,  slowshut, irisflag,  priSlowGain,  ssOnly);
      break;
  }  // end of switch (currobj)
  // 制御量が限界を超えたのに制御対象が変わらない場合制御量を変化させない
//  noChangeControl = (outOfLimit && (currobj == nextobj));	// 2014.08.08 制御量が限界を超えても演算は継続して行うため無効にする
  return nextobj;
}

CNTOBJ AXMIspAeBase::selectSubr_Shutter(CNTOBJ currobj, YLVLDISPL dir, bool slowshut,
        bool irisflag, bool priSlowGain, bool ssOnly) {
  CNTOBJ nextobj = currobj;
      switch (dir) {
        case YLVL_LOWER:	// 制御量がYレベルを下げる方向の場合
          if (isShutterLowerLimit() && irisflag) {
            nextobj = CNTOBJ_IRIS;  // アイリス制御に移行する①②
			irisCntl = irisUpper+1;	// irisCntrlを範囲内に入れる。irisUpper < irisLower

#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
            cout << TAG + "selectSubr:Iris<=Shutter" << endl;
  #endif
#endif
           }
          break;
        case YLVL_UPPER:
          if (isShutterUpperLimit()) {
            if (priSlowGain) {
              if (slowshut){
                nextobj = CNTOBJ_SLOWSHUT;		// 低速シャッター制御に移行する①③
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
                cout << TAG + "selectSubr:Shutter=>SlowShut" << endl;
  #endif
#endif
                }else {
                  if( ssOnly == false){
                    nextobj = CNTOBJ_GAIN;      // ゲイン制御に移行する②④⑤
      #ifndef PARASOFT_CPPTEST
        #ifndef COUT_DEBUG
                    cout << TAG + "selectSubr:Shutter=>Gain" << endl;
        #endif
      #endif

                  }
                }
            } else {
              nextobj = CNTOBJ_GAIN; 			// ゲイン制御に移行する②④⑤
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
              cout << TAG + "selectSubr:Shutter=>Gain" << endl;
  #endif
#endif
             }
           }
          break;
        case YLVL_UNCHANGE:
        default:
          break;
      }  //  end of switch(dir)
  return nextobj;
}

CNTOBJ AXMIspAeBase::selectSubr_Gain(CNTOBJ currobj, YLVLDISPL dir, bool slowshut,
        bool irisflag, bool priSlowGain, bool ssOnly) {
  CNTOBJ nextobj = currobj;
      switch (dir) {
        case YLVL_LOWER:	// 制御量がYレベルを下げる方向の場合
          if (isGainLowerLimit()) {
            if (priSlowGain && slowshut) {
                nextobj = CNTOBJ_SLOWSHUT;		// 低速シャッター制御に移行する①③
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
                cout << TAG + "selectSubr:SlowShut<=Gain" << endl;
  #endif
#endif
            } else {
              if(ssOnly == false){
                nextobj = CNTOBJ_SHUTSPED;		// シャッター制御に移行する②④⑤
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
                cout << TAG + "selectSubr:ShutterSpeed<=Gain" << endl;
  #endif
#endif
                }
              }
           }
          break;
        case YLVL_UPPER:
          if (isGainUpperLimit()) {
            if (slowshut && priSlowGain) {
              nextobj = CNTOBJ_SLOWSHUT;		// 低速シャッター制御に移行する②④
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
              cout << TAG + "selectSubr:Gain=>SlowShut" << endl;
  #endif
#endif
            }
          }
          break;
        case YLVL_UNCHANGE:
        default:
          break;
      }  //  end of switch(dir)
  return nextobj;
}

CNTOBJ AXMIspAeBase::selectSubr_SlowShutter(CNTOBJ currobj, YLVLDISPL dir, bool slowshut,
        bool irisflag, bool priSlowGain, bool ssOnly) {
  CNTOBJ nextobj = currobj;
      switch (dir) {
        case YLVL_LOWER:	// 制御量がYレベルを下げる方向の場合
          if (isSlowShutterLowerLimit()) {
            if (priSlowGain == true || ssOnly == true) {
              nextobj = CNTOBJ_SHUTSPED;		// シャッター制御に移行する①③
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
              cout << TAG + "selectSubr:ShutterSpeed<=SlowShut" << endl;
  #endif
#endif
            } else {
              nextobj = CNTOBJ_GAIN;			// ゲイン制御に移行する②④
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
              cout << TAG + "selectSubr:Gain<=SlowShut" << endl;
  #endif
#endif
            }
          }
          break;
        case YLVL_UPPER:
          if (isSlowShutterUpperLimit()) {
            if (priSlowGain == false && ssOnly == false) {
              nextobj = CNTOBJ_GAIN;			// ゲイン制御に移行する①③
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
              cout << TAG + "selectSubr:SlowShut=>Gain" << endl;
  #endif
#endif
            }
          }
          break;
        case YLVL_UNCHANGE:
        default:
          break;
      }  //  end of switch(dir)
  return nextobj;
}

CNTOBJ AXMIspAeBase::selectSubr_Iris(CNTOBJ currobj, YLVLDISPL dir, bool slowshut,
        bool irisflag, bool priSlowGain, bool ssOnly) {
  CNTOBJ nextobj = currobj;
      switch (dir) {
        case YLVL_UPPER:  // 制御量がYレベルを上げる方向の場合
          if (isIrisUpperLimit()) {
            nextobj = CNTOBJ_SHUTSPED;    // シャッター制御に移行する①②
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
            cout << TAG + "selectSubr:Iris=>ShutterSpeed" << endl;
  #endif
#endif
           }
          break;
        case YLVL_LOWER:  // 制御量がYレベルを下げる方向の場合
          if (isIrisLowerLimit()) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
            cout << TAG + "selectSubr:Iris limit" << endl;
  #endif
#endif
           }
          break;
        case YLVL_UNCHANGE:
        default:
          break;
      }  //  end of switch(dir)
  return nextobj;
}

bool AXMIspAeBase::isShutterLowerLimit(void) {
  outOfLimit = (shutterSpeed <= shutterSpeedLower);
  return outOfLimit;
}

bool AXMIspAeBase::isShutterUpperLimit(void) {
  outOfLimit = (shutterSpeed >= shutterSpeedUpper);
  return outOfLimit;
}

bool AXMIspAeBase::isGainLowerLimit(void) {
  outOfLimit = (gain <= gainLower);
  return outOfLimit;
}

bool AXMIspAeBase::isGainUpperLimit(void) {
  outOfLimit = (gain >= gainUpper);
  return outOfLimit;
}

bool AXMIspAeBase::isSlowShutterLowerLimit(void) {
  outOfLimit = (shutterSpeed <= slowShutterLower);

  return outOfLimit;
}

bool AXMIspAeBase::isSlowShutterUpperLimit(void) {
  outOfLimit = (shutterSpeed >= slowShutterUpper);
  return outOfLimit;
}

bool AXMIspAeBase::isIrisLowerLimit(void) {
  outOfLimit = (irisCntl >= irisLower);
  return outOfLimit;
}

bool AXMIspAeBase::isIrisUpperLimit(void) {
  outOfLimit = (irisCntl <= irisUpper);
  return outOfLimit;
}

void AXMIspAeBase::forceIrisOpen(AXMIspAeControlExposure *controlExposure) {
  if (forceIrisOpenCnt < 10) {
  	if(controlExposure != NULL){
		controlExposure->contIris = IRIS_CONT_OPEN_FAST;
		controlExposure->doControlExposure |= E_ISC_Iris;
  	}
  	forceIrisOpenCnt++;
  }
}

#ifdef WDR
AXMIspAeExposureRatioWDRMode::AXMIspAeExposureRatioWDRMode() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  TAG = "AXMIspAeExposureRatioWDRMode::";
  cout << TAG + "constructor" << endl;
  #endif
#endif
#ifdef IMX662
	wdrShutterSpeed = Exposure1PER60S;						// 1/60fps
#elif IMX415	// IMX662
	// IMX415用
	wdrShutterSpeed = Exposure1PER30S;						// 1/30fps
#else	// IMX662
	// IMX412用
	wdrShutterSpeed = Exposure1PER15S;						// 1/15fps
#endif	// IMX662
}

AXMIspAeExposureRatioWDRMode::~AXMIspAeExposureRatioWDRMode() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMIspAeExposureRatioWDRMode::notifyAeAlgorithm(AXMIspAeSetting *obj) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "notifyAeAlgorithm" << endl;
  #endif
#endif
  AXMIspAeBase::notifyAeAlgorithm(obj);	// 基底クラス呼出
  ptrAeSettingRef = obj;

  if(obj != NULL){
#ifdef IMX662
    shutterSpeedUpper = Exposure1PER60S;   // 1/60fps
#elif IMX415	// IMX662
	// IMX415用
    shutterSpeedUpper = Exposure1PER30S;   // 1/30fps
#else	// IMX662
	// IMX412用
    shutterSpeedUpper = Exposure1PER15S;   // 1/15fps
#endif	// IMX662
    shutterSpeedLower = Exposure1PER8000S; // 1/8000fps

    gainUpper = 12;	// 12dB

    irisLower = IRIS_MAX;          // 16
    irisUpper = 0;       // 1.4		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
	// WDRの短時間露光の場合目標値を通常の1/4にする
  	AeTarget = obj->objAeTarget.AeTarget.conv2Long() >> 1;		// AE目標値WDR実装に伴い追加	// 右シフト見直しobj->objAeTarget.AeTarget.conv2Long() >= 0 なので問題なし

  }
}

void AXMIspAeExposureRatioWDRMode::CalcWDRShortExposureTime(AXMIspAeControlExposure *controlExposure) {
    	// イメージセンサ制御
    beforeExposureTime = divBy10000(
        (beforeExposureTime * (10000L - AeControlValue))
            + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L, _TEN_THOUSAND -> 10000L）
#ifdef IMX662
    wdrShutterSpeed = divBy10000(
    	(beforeExposureTime * Exposure1PER60S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#elif IMX415	// IMX662
	// IMX415用
    wdrShutterSpeed = divBy10000(
    	(beforeExposureTime * Exposure1PER30S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#else	// IMX662
	// IMX412用
    wdrShutterSpeed = divBy10000(
    	(beforeExposureTime * Exposure1PER15S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）
#endif	// IMX662

	// シャッタースピードが範囲を超えた時のクリップ処理
	if(wdrShutterSpeed < Exposure1PER32000S){		// シャッタースピードが最小値を超える？
		wdrShutterSpeed = Exposure1PER32000S;	// シャッタースピード最小値にクリップする
#ifdef IMX662
		beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER60S >> 1)) / Exposure1PER60S;	// 右シフト見直しExposure1PER60S >= 0 なので問題なし
#elif IMX415	// IMX662
		// IMX415用
		beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER30S >> 1)) / Exposure1PER30S;	// 右シフト見直しExposure1PER30S >= 0 なので問題なし
#else	// IMX662
		// IMX412用
		beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER15S >> 1)) / Exposure1PER15S;	// 右シフト見直しExposure1PER15S >= 0 なので問題なし
#endif	// IMX662
	}
	unsigned int wdrShutterSpeedUpper = ((Exposure1PER15S * 0x40) + (ExposureRatio>>1)) / ExposureRatio;	// 露光比率は64倍されているため積算したあと64で割る	// 右シフト見直し((Exposure1PER32000S * ExposureRatio) + 32) >= 0 なので問題なし
																											// 右シフト見直しExposureRatio >= 0 なので問題なし
	if(wdrShutterSpeed > wdrShutterSpeedUpper){		// シャッタースピードが最大値を超える？
		wdrShutterSpeed = wdrShutterSpeedUpper;	// シャッタースピード最大値にクリップする
#ifdef IMX662
		beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER60S >> 1)) / Exposure1PER60S;	// 右シフト見直しExposure1PER60S >= 0 なので問題なし
#else
		beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER15S >> 1)) / Exposure1PER15S;	// 右シフト見直しExposure1PER15S >= 0 なので問題なし
#endif
	}

}

void AXMIspAeExposureRatioWDRMode::DecideWDRShortControlValue(AXMIspAeControlExposure *controlExposure) {
	// WDR露光時間計算

	controlExposure->doControlExposure = E_ISC_ShutterSpeed;
	shutterSpeed = wdrShutterSpeed;
;
	if(isIrisUpperLimit() == false){		// シャッタースピードが最小値を超える？
#ifdef MECHA_IRIS
			controlExposure->doControlExposure |= E_ISC_Iris;

    	JudgeIrisRegion(controlExposure, true);		// 最小値を超える分はアイリスで制御する for debug
#endif
		} else {
		CalcWDRShortExposureTime(controlExposure);
		shutterSpeed = wdrShutterSpeed;
		// シャッタースピードが範囲を超えた時のクリップ処理
		if(shutterSpeed < Exposure1PER8000S){		// シャッタースピードが最小値を超える？
			irisCntl = irisUpper+1;	// irisCntrlを範囲内に入れる。irisUpper < irisLower
		}
	}
	if(shutterSpeed < Exposure1PER8000S){		// シャッタースピードが最小値を超える？
		shutterSpeed = Exposure1PER8000S;		// シャッタースピード最小値にクリップする
	}
	controlExposure->contShutter = shutterSpeed;
	controlExposure->contGain = 0;
	// モード切替後の数フレームはアイリスを開放する。
	forceIrisOpen(controlExposure);
	// WDR長時間露光時は0クリア
	setAECalcData(0);
  	setAECalcData2(0);
	setAEControlValue(0);


}

void AXMIspAeExposureRatioWDRMode::DecideWDRLongControlValue(AXMIspAeControlExposure *controlExposure) {

		controlExposure->doControlExposure = E_ISC_ShutterSpeed;
	// WDR露光時間計算
		shutterSpeed = wdrShutterSpeed;

	// シャッタースピードが範囲を超えた時のクリップ処理
	if(shutterSpeed < Exposure1PER8000S){		// シャッタースピードが最小値を超える？
		shutterSpeed = Exposure1PER8000S;		// シャッタースピード最小値にクリップする
		
	}
	
	shutterSpeed = ((shutterSpeed * ExposureRatio) + 32) >> 6;	// 露光比率は64倍されているため積算したあと64で割る// 右シフト見直し((Exposure1PER32000S * ExposureRatio) + 32) >= 0 なので問題なし
	gain = 0;
	if(shutterSpeed > Exposure1PER15S){		// WDRシャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER15S;
	}
#ifdef IMX662
	if(shutterSpeed > Exposure1PER60S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER60S;	// シャッタースピード最大値にクリップする
#elif IMX415	// IMX662
	// IMX415用
	if(shutterSpeed > Exposure1PER30S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER30S;	// シャッタースピード最大値にクリップする
#else	// IMX662
	// IMX412用
	if(shutterSpeed > Exposure1PER15S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER15S;	// シャッタースピード最大値にクリップする
#endif	// IMX662
	// 超えた分を露光比率で調整する
		if (ptrAeSettingRef != NULL) {
			ptrAeSettingRef->objAeWDRChara.adjustExposureRatio = ((shutterSpeed * 0x0040) + (wdrShutterSpeed >> 1))/ wdrShutterSpeed;
		}
	} else {
		if (ptrAeSettingRef != NULL) {
			ptrAeSettingRef->objAeWDRChara.adjustExposureRatio = ExposureRatio;
		}
	}
	// ptrAeSettingRef->objAeWDRChara.adjustExposureRatioの値はp_spec->AE.mixExpRatioに０以外の値が設定されればそちらが優先される。
	controlExposure->contShutter = shutterSpeed;
	controlExposure->contGain = gain;
	// モード切替後の数フレームはアイリスを開放する。
	forceIrisOpen(controlExposure);
}

void AXMIspAeExposureRatioWDRMode::WDRCalcLuminanceValue(AXMIspAeControlExposure *controlExposure , ST_FROM_AE_TO_ISP *execFromAeToIsp) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "CalcLuminanceValue" << endl;
  #endif
#endif
	unsigned int shutter = ((wdrShutterSpeed * ExposureRatio)>>7);	// 短時間露光時のシャッタースピードに露光比率/2を	// 右シフト見直し(wdrShutterSpeed * ExposureRatio) >= 0 なので問題なし
	LONG luminance = Exposure1S;
	// 明るさデータ = 5/露光時間/ゲイン（リニア）
	if(shutter > 1){
		luminance = (luminance + (shutter >> 1)) / shutter;	// Exposure1S / shutter シャッタースピードの逆数　1/60なら60	// 右シフト見直しshutter >= 0 なので問題なし
	}
	luminance = luminance * 5;
	if(luminance > 0x0000FFFF){
		luminance = 0x0000FFFF;
	}
	execFromAeToIsp->luminance = static_cast<unsigned short>(luminance);
}

AXMIspAeAutoWDR::AXMIspAeAutoWDR() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  TAG = "AXMIspAeAutoWDR::";
  cout << TAG + "constructor" << endl;
  #endif
#endif

#ifdef IMX662
   wdrShutterSpeed = Exposure1PER60S;
  	SelectBL_CorFLC = 0;
	wdrShortShutterSpeed = Exposure1PER60S;
	wdrLongShutterSpeed = Exposure1PER60S;
#elif IMX415	// IMX662
	// IMX415用
	wdrShutterSpeed = Exposure1PER30S;
  	SelectBL_CorFLC = 0;
	wdrShortShutterSpeed = Exposure1PER30S;
	wdrLongShutterSpeed = Exposure1PER30S;
#else	// IMX662
	// IMX412用
	wdrShutterSpeed = Exposure1PER15S;
  	SelectBL_CorFLC = 0;
	wdrShortShutterSpeed = Exposure1PER15S;
	wdrLongShutterSpeed = Exposure1PER15S;
#endif	// IMX662
	beforeShortExposureTime = 10000L;		// 初期値100%	// 露光時間		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
	beforeLongExposureTime = 10000L;		// 初期値100%	// 露光時間		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
	newRatio = 0x0040;

}

AXMIspAeAutoWDR::~AXMIspAeAutoWDR() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "destructor" << endl;
  #endif
#endif
}

void AXMIspAeAutoWDR::notifyAeAlgorithm(AXMIspAeSetting *obj) {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << TAG + "notifyAeAlgorithm" << endl;
  #endif
#endif
  AXMIspAeBase::notifyAeAlgorithm(obj);	// 基底クラス呼出
  ptrAeSettingRef = obj;

  if(obj != NULL){
#ifdef IMX662
    shutterSpeedUpper = Exposure1PER60S;   // 1/60fps
#elif IMX415	// IMX662
	// IMX415用
    shutterSpeedUpper = Exposure1PER30S;   // 1/30fps
#else	// IMX662
	// IMX412用
    shutterSpeedUpper = Exposure1PER15S;   // 1/15fps
#endif	// IMX662
    shutterSpeedLower = Exposure1PER8000S; // 1/8000fps

    irisLower = IRIS_MAX;          // 16
    irisUpper = 0;       // 1.4		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  }
}

void AXMIspAeAutoWDR::SetAutoWDRShortTarget(void) {

	AeTarget = 128L;
	if (ptrAeSettingRef != NULL) {
		AeTarget = ptrAeSettingRef->objAeWDRChara.AutoWDRShortExposureTarget;
	}
}

void AXMIspAeAutoWDR::SetAutoWDRLongTarget(void) {

	AeTarget = 512L;
	if (ptrAeSettingRef != NULL) {
		AeTarget = ptrAeSettingRef->objAeWDRChara.AutoWDRLongExposureTarget;
	}
}

void AXMIspAeAutoWDR::CalcAutoWDRShortAverage(AXMIspAeControlExposure *controlExposure) {
#if 1
	if (ptrAeSettingRef != NULL) {
		ptrAeSettingRef->objAeWDRChara.adjustExposureRatio = newRatio;
		ULONG ratio;
		if(wdrLongShutterSpeed >= wdrShortShutterSpeed) {
			ratio = (wdrLongShutterSpeed * 0x0040);
			if(wdrShortShutterSpeed > 1){
				ratio = (ratio + (wdrShortShutterSpeed >> 1))/ wdrShortShutterSpeed;
			}
			if(ratio > 0x00000FFFL) {
				ratio = 0x00000FFFL;
				wdrLongShutterSpeed = ((wdrShortShutterSpeed * ratio) + 0x0020) / 0x0040;
			}
		}else {
			ratio = (wdrShortShutterSpeed * 0x0040);
			if(wdrLongShutterSpeed > 1){
				ratio = (ratio + (wdrLongShutterSpeed >> 1))/ wdrLongShutterSpeed;
			}
			if(ratio > 0x00000FFFL) {
				ratio = 0x00000FFFL;
				wdrShortShutterSpeed = ((wdrLongShutterSpeed * ratio) + 0x0020) / 0x0040;
			}
		}
		newRatio = ratio;
	}
#endif
	
	OpdYAve = (LONG)(OpdYHighLumiAreaAve * 10);		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
}

void AXMIspAeAutoWDR::CalcAutoWDRLongAverage(AXMIspAeControlExposure *controlExposure) {
	OpdYAve = (LONG)(OpdYLowLumiAreaAve * 10);		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
	
	SHORT bin;

	for ( bin = 0; bin < HISTMAX ; bin++ ) {
		setHistogramLog(bin , Histogram[bin].weighted);
		setHistogramLog2(bin , (Histogram[bin].pv_flag << 8)  | (Histogram[bin].eval));
	}
	setHistogramLog2(bin , histDivFrequency);


}

void AXMIspAeAutoWDR::CalcAutoWDRExposureTime(AXMIspAeControlExposure *controlExposure , ULONG *beforeExposureTime) {
    	// イメージセンサ制御
    *beforeExposureTime = divBy10000(
        (*beforeExposureTime * (10000L - AeControlValue))
            + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L, _TEN_THOUSAND -> 10000L）
#ifdef IMX662
    wdrShutterSpeed = divBy10000(
    	(*beforeExposureTime * Exposure1PER60S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）

	// シャッタースピードが範囲を超えた時のクリップ処理
	if(wdrShutterSpeed < Exposure1PER32000S){		// シャッタースピードが最小値を超える？
		wdrShutterSpeed = Exposure1PER32000S;	// シャッタースピード最小値にクリップする
		*beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER60S >> 1)) / Exposure1PER60S;	// 右シフト見直しExposure1PER60S >= 0 なので問題なし
	}
																											// 右シフト見直しExposureRatio >= 0 なので問題なし
	if(wdrShutterSpeed > Exposure1PER15S){		// シャッタースピードが最大値を超える？
		wdrShutterSpeed = Exposure1PER15S;	// シャッタースピード最大値にクリップする
		*beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER60S >> 1)) / Exposure1PER60S;	// 右シフト見直しExposure1PER60S >= 0 なので問題なし
	}
#elif IMX415
	// IMX415用
    wdrShutterSpeed = divBy10000(
    	(*beforeExposureTime * Exposure1PER30S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）

	// シャッタースピードが範囲を超えた時のクリップ処理
	if(wdrShutterSpeed < Exposure1PER32000S){		// シャッタースピードが最小値を超える？
		wdrShutterSpeed = Exposure1PER32000S;	// シャッタースピード最小値にクリップする
		*beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER30S >> 1)) / Exposure1PER30S;	// 右シフト見直しExposure1PER30S >= 0 なので問題なし
	}
																											// 右シフト見直しExposureRatio >= 0 なので問題なし
	if(wdrShutterSpeed > Exposure1PER30S){		// シャッタースピードが最大値を超える？
		wdrShutterSpeed = Exposure1PER30S;	// シャッタースピード最大値にクリップする
		*beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER30S >> 1)) / Exposure1PER30S;	// 右シフト見直しExposure1PER30S >= 0 なので問題なし
	}
#else	// IMX662
	// IMX412用
    wdrShutterSpeed = divBy10000(
    	(*beforeExposureTime * Exposure1PER15S) + 5000L);		// ※コンパイラ都合によりenumから数値に変更（_FIVE_THOUSAND -> 5000L）

	// シャッタースピードが範囲を超えた時のクリップ処理
	if(wdrShutterSpeed < Exposure1PER32000S){		// シャッタースピードが最小値を超える？
		wdrShutterSpeed = Exposure1PER32000S;	// シャッタースピード最小値にクリップする
		*beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER15S >> 1)) / Exposure1PER15S;	// 右シフト見直しExposure1PER15S >= 0 なので問題なし
	}
																											// 右シフト見直しExposureRatio >= 0 なので問題なし
	if(wdrShutterSpeed > Exposure1PER15S){		// シャッタースピードが最大値を超える？
		wdrShutterSpeed = Exposure1PER15S;	// シャッタースピード最大値にクリップする
		*beforeExposureTime = ((wdrShutterSpeed * 10000) + (Exposure1PER15S >> 1)) / Exposure1PER15S;	// 右シフト見直しExposure1PER15S >= 0 なので問題なし
	}
#endif	// IMX662
}

void AXMIspAeAutoWDR::DecideAutoWDRShortControlValue(AXMIspAeControlExposure *controlExposure) {
	controlExposure->doControlExposure = E_ISC_ShutterSpeed;
	shutterSpeed = wdrShortShutterSpeed;
	if(isIrisUpperLimit() == false){		// シャッタースピードが最小値を超える？
#ifdef MECHA_IRIS
			controlExposure->doControlExposure |= E_ISC_Iris;

    	JudgeIrisRegion(controlExposure, true);		// 最小値を超える分はアイリスで制御する for debug
#endif
		} else {
		CalcAutoWDRExposureTime(controlExposure , &beforeShortExposureTime);
		shutterSpeed = wdrShutterSpeed;
		// シャッタースピードが範囲を超えた時のクリップ処理
		if(shutterSpeed < Exposure1PER8000S){		// シャッタースピードが最小値を超える？
			irisCntl = irisUpper+1;	// irisCntrlを範囲内に入れる。irisUpper < irisLower
		}
	}
	if(shutterSpeed < Exposure1PER8000S){		// シャッタースピードが最小値を超える？
		shutterSpeed = Exposure1PER8000S;		// シャッタースピード最小値にクリップする
	}
#ifdef IMX662
	if(shutterSpeed > Exposure1PER60S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER60S;	// シャッタースピード最大値にクリップする
	}
#elif IMX415
	// IMX415用
	if(shutterSpeed > Exposure1PER30S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER30S;	// シャッタースピード最大値にクリップする
	}
#else	// IMX662
	// IMX412用
	if(shutterSpeed > Exposure1PER15S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER15S;	// シャッタースピード最大値にクリップする
	}
#endif	// IMX662
	controlExposure->contShutter = wdrShortShutterSpeed;
	controlExposure->contGain = 0;
	// モード切替後の数フレームはアイリスを開放する。
	forceIrisOpen(controlExposure);
	// WDR長時間露光時は0クリア


	wdrShortShutterSpeed = shutterSpeed;

  	setAECalcData1(OpdYAve.conv2Long());
  	setAEMainObj( OpdYHighLumiAreaAve, OpdYLowLumiAreaAve , histDivPoint | (2 << 16));
	
	// 今回存在しないため不要
	/*
  	setRegLog(GetReg32(RegSPU_C) , GetReg32(RegMIX_EXP_RATIO));
	*/
}

void AXMIspAeAutoWDR::DecideAutoWDRLongControlValue(AXMIspAeControlExposure *controlExposure) {

		controlExposure->doControlExposure = E_ISC_ShutterSpeed;
	// WDR露光時間計算
		CalcAutoWDRExposureTime(controlExposure , &beforeLongExposureTime);
		shutterSpeed = wdrShutterSpeed;

	// シャッタースピードが範囲を超えた時のクリップ処理
	if(shutterSpeed < Exposure1PER8000S){		// シャッタースピードが最小値を超える？
		shutterSpeed = Exposure1PER8000S;		// シャッタースピード最小値にクリップする
		
	}
	
	gain = 0;
#ifdef IMX662
	if(shutterSpeed > Exposure1PER60S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER60S;	// シャッタースピード最大値にクリップする
	// 超えた分を露光比率で調整する
	}
#elif IMX415
	// IMX415用
	if(shutterSpeed > Exposure1PER30S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER30S;	// シャッタースピード最大値にクリップする
	// 超えた分を露光比率で調整する
	}
#else	// IMX662
	// IMX412用
	if(shutterSpeed > Exposure1PER15S){		// シャッタースピードが最大値を超える？
		shutterSpeed = Exposure1PER15S;	// シャッタースピード最大値にクリップする
	// 超えた分を露光比率で調整する
	}
#endif	// IMX662
	controlExposure->contShutter = wdrLongShutterSpeed;
	controlExposure->contGain = gain;
	// モード切替後の数フレームはアイリスを開放する。
	forceIrisOpen(controlExposure);


	wdrLongShutterSpeed = shutterSpeed;
  	setAECalcData1(OpdYAve.conv2Long());
  	setAEMainObj( OpdYHighLumiAreaAve, OpdYLowLumiAreaAve , histDivPoint | (4 << 16));
	// 今回存在しないため不要
	/*
		setRegLog(GetReg32(RegSPU_C) , GetReg32(RegMIX_EXP_RATIO));
	*/
}
#endif
#ifdef PARASOFT_CPPTEST
void AXMIspAeBase::setIrisValueFrame(SHORT currentAeDiffFrameNo , SHORT beforeAeDiffFrameNo) {
	result[0] = currentAeDiffFrameNo = currentAeDiffFrameNo;
	result[1] = beforeAeDiffFrameNo = beforeAeDiffFrameNo;
}

void AXMIspAeBase::setIrisValueDiff(LONG currentAeDiff , LONG beforeAeDiff) {
	result[2] = currentAeDiff = currentAeDiff;
	result[3] = beforeAeDiff = beforeAeDiff;
}

void AXMIspAeBase::setIrisValueAbsDiff(LONG absIdif) {
	result[4] = absIdif = absIdif;
}

void AXMIspAeBase::setIrisValue(LONG absTh1 , LONG absTh2 ) {
	result[5] = absTh1 = absTh1;
	result[6] = absTh2 = absTh2;
}
#endif	// PARASOFT_CPPTEST


