/*
 * AXMTestState.cpp
 */

#include "AXMTest.hpp"
#include "../AXMCommon/AXMCommonSetParam.hpp"
#include "../AXMCommon/AXMCommonStruct.hpp"

#include <sstream>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <string.h>

#ifdef USE_AXFTEST_COMMAND_COMPLOG
#include "AXMScenarioTest.hpp"
#endif /* USE_AXFTEST_COMMAND_COMPLOG */

// STATE_RUNNING状態の状態テーブル定義
//      {イベントID, メンバ関数ポインタ}
//      ...
//     {0,NULL}
const AXMTest::StateTable AXMTest::state_running[] = {
    { EVENT_AXCOMM_TEST, (AXMTest::StateFuncPtr) &AXMTest::funcAxcommTest },
    { EVENT_LOOPBACK_TEST, (AXMTest::StateFuncPtr) &AXMTest::funcLoopbackTest },
    { EVENT_STARTLOOPBACK_TEST, (AXMTest::StateFuncPtr) &AXMTest::funcStartLoopbackTest },
    { EVENT_STOPLOOPBACK_TEST, (AXMTest::StateFuncPtr) &AXMTest::funcStopLoopbackTest },
    { EVENT_STARTLOOPBACK_ALL, (AXMTest::StateFuncPtr) &AXMTest::funcStartLoopbackAll },
    { EVENT_STOPLOOPBACK_ALL, (AXMTest::StateFuncPtr) &AXMTest::funcStopLoopbackAll },
    { EVENT_TIMER_TEST, (AXMTest::StateFuncPtr) &AXMTest::funcTimerTest },
    { EVENT_WATCHDOG_TIMEOUT_TEST, (AXMTest::StateFuncPtr) &AXMTest::funcWatchdogTimeoutTest },
#ifdef USE_AXFTEST_COMMAND
    { EVENT_SAMPLE_SCRIPT_HANDLER1, (AXMTest::StateFuncPtr) &AXMTest::funcSampleScriptHandler1 },
    { EVENT_SAMPLE_SCRIPT_HANDLER2, (AXMTest::StateFuncPtr) &AXMTest::funcSampleScriptHandler2 },
    { EVENT_SAMPLE_SCRIPT_HANDLER3, (AXMTest::StateFuncPtr) &AXMTest::funcSampleScriptHandler3 },
    { EVENT_SAMPLE_SCRIPT_HANDLER4, (AXMTest::StateFuncPtr) &AXMTest::funcSampleScriptHandler4 },
    { EVENT_SAMPLE_SCRIPT_HANDLER5, (AXMTest::StateFuncPtr) &AXMTest::funcSampleScriptHandler5 },
#endif /* USE_AXFTEST_COMMAND */
#ifdef USE_AXFTEST_COMMAND_COMPLOG
    { EVENT_SCENARIOTEST_ISP_TIMEOUT, (AXMTest::StateFuncPtr) &AXMTest::funcScenarioTestIspTimeout},
    { EVENT_SCENARIOTEST_AX_TIMEOUT, (AXMTest::StateFuncPtr) &AXMTest::funcScenarioTestAxTimeout},
#endif /* USE_AXFTEST_COMMAND_COMPLOG */
    { 0, NULL } };

ax::actorFuncStatus AXMTest::funcAxcommTest(const void *pParam, int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcAxcommTest()");
  m_log.write(AXFLOG_INFO, (char*) pParam);
  return ax::AXFACTOR_SUCCESS;
}

#define TICK_PER_SEC    60000
#define BUF_SZ          256

// 1つのテストパケットが転送される回数
#define CNT_N           8

// エージングテスト用のActor名の配列 names[] に関して
// インデックス値として指定する整数値のビット幅
#define NAMES_N_BIT_W   3

// エージングテスト用のActor名の配列 names[] に関して
// 配列の要素数
#define NAMES_N         (1 << NAMES_N_BIT_W)

// テストパケット先頭の宛先リスト部のバイト数
//   CNT_N = 8, NAMES_N_BIT_W = 3 の場合では 3バイト
#define HEAD_LIST_BYTES ((NAMES_N_BIT_W * CNT_N + 7) / 8)

// サイズ sz バイトのテストパケットの
// チェックサムの格納されてる位置(バイトオフセット)
#define CKSUM_POS(sz)   ((sz) - 2)

// テストパケットに格納されてる
// チェックサムの長さ(バイト数)
#define CKSUM_LEN       2

// サイズ sz バイトのテストパケットの
// 転送カウンタの格納されてる位置(バイトオフセット)
#define CNT_POS(sz)     ((sz) - 3)

// テストパケットに格納されてる
// 転送カウンタの長さ(バイト数)
#define CNT_LEN         1

// テストパケットの先頭部分の内容を、
// そのパケットの識別IDとして取り扱う。
// その識別IDとして取り扱う長さ(バイト数)
#define PKT_ID_BYTES    4

// 配列 names[]
//   エージングテスト用のActor名一覧
//   axStage は ARM側で動作
//   ispStage は Xtensa側で動作
//
static AXFObjectName names[NAMES_N] = {
    AXFObjectName("axtest", "axStage"),
    AXFObjectName("axtest2", "axStage"),
    AXFObjectName("axtest3", "axStage"),
    AXFObjectName("axtest4", "axStage"),
    AXFObjectName("axtest", "ispStage"),
    AXFObjectName("axtest2", "ispStage"),
    AXFObjectName("axtest3", "ispStage"),
    AXFObjectName("axtest4", "ispStage"),
};

// getObjectNameMaxLen
//   配列 names[] 内の AXFObjectNameインスタンスについて、
//   getFullActorName()メソッドで返す文字列の最大長を返す
//
static int getObjectNameMaxLen() {
  static int ret = 0;
  if (ret)
    return ret;
  int id;
  for (id = 0; id < NAMES_N; id++) {
    int sz = names[id].getFullActorName().size();
    if (sz > ret)
      ret = sz;
  }
  return ret;
}

// getLE
//   buf から bytes バイトの領域に、
//   リトル・エンディアンのバイトオーダーで配置された
//   bytesバイトの整数を取得し返す
// 
//   bytes 指定の有効範囲は 1 から sizeof(int) まで
//
// 例
//   buf[0] = 0x78, buf[1] = 0x56, buf[2] = 0x34, bytes = 3 の場合
//   値 0x345678 を返す
//
static int getLE(unsigned char *buf, int bytes) {
  int v = 0;
  while (--bytes >= 0) {
    v <<= 8;
    v |= static_cast<int>(buf[bytes]);
  }
  return v;
}

// setLE
//   整数 v の下位 (bytes * 8) ビットの値を、
//   buf から bytes バイトの領域に、
//   リトル・エンディアンのバイトオーダーで配置する
//
//   bytes 指定の有効範囲は 1 から sizeof(int) まで
//
// 例
//   bytes = 3, v = 0x12345678 を指定した場合
//   buf[0] = 0x78, buf[1] = 0x56, buf[2] = 0x34 が設定される
//
static void setLE(unsigned char *buf, int bytes, int v) {
  for (int i = 0; i < bytes; i++) {
    buf[i] = v & 255;
    v >>= 8;
  }
}

// getCntName
//   bufに格納されているテストパケットについて、
//   パケット先頭の宛先リスト部を参照し、
//   転送カウンタ値 cnt に対応する宛先(Actor名)を返す
//
static AXFObjectName& getCntName(unsigned char *buf, int cnt) {
  int id = (getLE(buf, HEAD_LIST_BYTES) >> (cnt * NAMES_N_BIT_W)) & (NAMES_N - 1);
  return names[id];
}

// calcCkSum
//   bufに格納されている sizeバイトのテストパケットについて、
//   チェックサムを算出して返す
//
//   パケット末尾のチェックサムを格納する領域は、
//   チェックサム算出の対象外
//
static int calcCkSum(unsigned char *buf, int size) {
  int i, sum = 0;
  for (i = 0; i < CKSUM_POS(size); i++)
    sum += buf[i];
  return sum & ((1 << (CKSUM_LEN * 8)) - 1);
}


// AXMTest::funcLoopbackTest
//   エージングテスト用のイベント EVENT_LOOPBAK_TEST で呼び出される
//   イベントハンドラ
//
//   テストパケットを受け取りパケットの内容が妥当か判定する。
//
//   テストパケットは転送ごとに転送カウンタ値を増加させ、
//   次の転送先のActorへと送られる
//
//   テストパケットの生成は、funcStartLoopbackTest で行われ、
//   生成したパケットの識別IDが記録されている
//
//   最後の転送先は、そのパケットを生成したActorに戻るように、
//   予め指定されている
//
//   最後の転送を終えたパケットは、そのパケットを生成したActorに戻り、
//   識別IDが妥当か判定される
//
ax::actorFuncStatus AXMTest::funcLoopbackTest(const void *pParam, int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcLoopbackTest()");

  unsigned char buf[BUF_SZ];

  // パケット長の最大値の判定
  if (size > (int) sizeof(buf)) {
    m_log.write(AXFLOG_ERR, "fail size > BUF_SZ");
    return ax::AXFACTOR_ERROR;
  }

  memcpy(buf, pParam, size);

  // チェックサムの判定
  if (CKSUM_POS(size) < 0) {
    m_log.write(AXFLOG_ERR, "fail CKSUM_POS < 0");
    return ax::AXFACTOR_ERROR;
  }
  int cksum = getLE(&buf[CKSUM_POS(size)], CKSUM_LEN);
  int sum = calcCkSum(buf, size);
  if (sum != cksum) {
    m_log.write(AXFLOG_ERR, "fail sum != cksum");
    return ax::AXFACTOR_ERROR;
  }

  // 転送カウンタ値の判定
  if (CNT_POS(size) < 0) {
    m_log.write(AXFLOG_ERR, "fail CNT_POS < 0");
    return ax::AXFACTOR_ERROR;
  }
  int cnt = buf[CNT_POS(size)];
  if (cnt >= CNT_N) {
    m_log.write(AXFLOG_ERR, "fail cnt >= CNT_N");
    return ax::AXFACTOR_ERROR;
  }

#ifdef NEVER // for debug
  {
    std::ostringstream oss;
    oss << "cnt=" << cnt << " d24=" << std::hex << getLE(buf, HEAD_LIST_BYTES);
    m_log.write(AXFLOG_ERR, oss.str());
  }
#endif
  // パケットの宛先の判定
  if (!getCntName(buf, cnt).isMatch(m_name)) {
    m_log.write(AXFLOG_ERR, "fail name != me");
    return ax::AXFACTOR_ERROR;
  }

  // そのパケットが最後の転送を終えたか判定
  if (cnt == CNT_N - 1) {
    // そのパケットが最後の転送を終えた場合

    // 生成したパケットの識別IDのリストに含まれているか確認する
    std::vector<int>::iterator it = std::find(m_vec.begin(), m_vec.end(),
                                         getLE(buf, PKT_ID_BYTES));
    if (it == m_vec.end()) {
      // 生成したパケットの識別IDのリストに含まれてない場合
      m_log.write(AXFLOG_ERR, "fail cnt == CNT_N - 1, not found");
      return ax::AXFACTOR_ERROR;
    }

    // 生成したパケットの識別IDのリストから削除
    m_vec.erase(it);
    m_loopbackCount++;
    std::ostringstream oss;
    oss << "loopbackCount=" << m_loopbackCount;
#ifdef USE_AXFTEST_COMMAND_COMPLOG
    if(m_loopbackCount == AXMScenarioTest::mLoopbackTestTime) {
      AXMScenarioTest::getInstance()->writeLog(&m_log, AXMScenarioTest::RESULT_SUCCESS);
    }
#endif /* USE_AXFTEST_COMMAND_COMPLOG */
    m_log.write(AXFLOG_NOTICE, oss.str());
    return ax::AXFACTOR_SUCCESS;
  }

  // この位置では
  // そのパケットの次の転送先がある状態

  // 転送カウンタ値を増加し、次の転送先へと転送する
  buf[CNT_POS(size)] = ++cnt;

  // パケット内の転送カウンタ値を増加したので、
  // チェックサムを算出しなおして更新
  sum = calcCkSum(buf, size);
  setLE(&buf[CKSUM_POS(size)], CKSUM_LEN, sum);

  // 次の転送先にエージングテスト用のイベント EVENT_LOOPBAK_TESTを送信し
  // パケットを転送する
  AXFObjectName toName = getCntName(buf, cnt);
  if (send(toName, (AXFEvent_t) EVENT_LOOPBACK_TEST, (void *) buf, size) < 0) {
    m_log.write(AXFLOG_ERR, "fail send loopback");
    return ax::AXFACTOR_ERROR;
  }
  return ax::AXFACTOR_SUCCESS;
}


// AXMTest::funcStartLoopbackTest
//   エージングテスト開始用のイベント EVENT_STARTLOOPBAK_TEST で呼び出される
//   イベントハンドラ
//
//   テストパケットを生成し、先頭の宛先にパケットを送信する
//
//   乱数で期間を指定して単発タイマーを設定し、
//   タイマー満了後に再び本イベントハンドラが
//   呼び出されるようにする
//
ax::actorFuncStatus AXMTest::funcStartLoopbackTest(const void *pParam,
                                                   int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcStartLoopbackTest()");

  // タイマーにより送信されたイベントかどうかを判定
  if (m_timerId == 0) {
    // タイマーにより送信されたイベントでない場合
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
    m_chronoStart = getCurrentTime();
#endif
    m_loopbackCount = 0;
  } else {
    // タイマーにより送信されたイベントの場合

    // タイマー満了後の後処理 (本来不要であるが暫定対応)
    if (stopSingleShotTimer(m_timerId) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail stop timer");
      return ax::AXFACTOR_ERROR;
    }
  }
#ifdef USE_AXFTEST_COMMAND_COMPLOG
  if(m_isLoopback == false) {
    //テスト開始を設定
    AXMScenarioTest::getInstance()->setTestCase(AXMScenarioTest::TEST_STARTLB);
  }
#endif /* USE_AXFTEST_COMMAND_COMPLOG */
  m_isLoopback = true;

  unsigned char buf[BUF_SZ];

  // テストパケットデータを生成する

  /*
   * AXFComm packet format
   *   | totalSize(4) | ObjectNameString(NULL stop) | eventID(4) | dataSize(4) | data ... |
   */
  int hlen = 4 + getObjectNameMaxLen() + 1 + 4 + 4;

  // 上記CPU間通信のデータフォーマットについて、
  // 末尾の data ... 部分に格納するテストパケットデータを生成する

  /*
   * Loopback test packet format (data ...)
   *   | head_list (HEAD_LIST_BYTES) | random data ... | cnt (CNT_LEN) | check sum (CKSUM_LEN) |
   *
   * head_list (destination list)
   *   NAMES_N_BIT_W * CNT_N
   */

  // テストパケットデータの構成は上記の通り
  // 先頭に宛先リスト部 (バイト数 HEAD_LIST_BYTES) が配置される
  // その後続に乱数データが配置される
  // その後続に転送カウンタ部が配置される
  // 末尾にチェックサム部が配置される

  // 先頭の宛先リスト部は
  // 1つの宛先を示すビット幅は NAMES_N_BIT_W ビット (3ビットで 0から7の値をとる)
  // CNT_N回転送するのでリスト全体は NAMES_N_BIT_W * CNT_Nビット (3 * 8 = 24ビット, 3バイト)


  // テストパケット長を乱数で決める
  int dlen = sizeof(buf) - hlen;
  if (dlen <= 0) {
    m_log.write(AXFLOG_ERR, "fail, dlen <= 0");
    return ax::AXFACTOR_ERROR;
  }
  int dlen_min = HEAD_LIST_BYTES + 4 + CKSUM_LEN + CNT_LEN;
  if (dlen <= dlen_min) {
    m_log.write(AXFLOG_ERR, "fail, dlen <= dlen_min");
    return ax::AXFACTOR_ERROR;
  }
  size = dlen_min + rand() % (dlen - dlen_min);


  // 先頭の宛先部と後続の乱数データを
  // 乱数で生成する
  int i;
  for (i = 0; i < CNT_POS(size); i++)
    buf[i] = rand() % 256;

  // この処理を実行してるActorの名前が
  // テスト用のActor名一覧 (配列 names[]) に
  // 含まれているか確認する
  int id;
  for (id = 0; id < NAMES_N; id++)
    if (m_name.isMatch(names[id]))
      break;
  if (id >= NAMES_N) {
    m_log.write(AXFLOG_ERR, "fail, not found my name");
    return ax::AXFACTOR_ERROR;
  }

  // 乱数で生成したパケット先頭の宛先リスト部について
  // 最後の転送先が、自身になるように修正する
  // set my name to last destination
  int cnt = CNT_N - 1;
  int d24 = getLE(buf, HEAD_LIST_BYTES);
  d24 &= ~((NAMES_N - 1) << (cnt * NAMES_N_BIT_W));
  d24 |= id << (cnt * NAMES_N_BIT_W);
  setLE(buf, HEAD_LIST_BYTES, d24);

#ifdef NEVER // for debug
  std::ostringstream oss;
  oss << "d24=" << std::hex << getLE(buf, HEAD_LIST_BYTES) << std::endl;
  for (cnt=0; cnt<CNT_N; cnt++) {
    oss << cnt << ":" << getCntName(buf, cnt).getFullActorName() << std::endl;
  }
  m_log.write(AXFLOG_INFO, oss.str());
#endif

  // 転送カウンタ部を初期化
  cnt = 0;
  buf[CNT_POS(size)] = cnt;

  // チェックサムを算出
  int sum = calcCkSum(buf, size);
  setLE(&buf[CKSUM_POS(size)], CKSUM_LEN, sum);

  // 生成したパケットについて
  // 先頭 PKT_ID_BYTES (4) バイトの内容を
  // パケット識別IDとして、リストへ登録
  // 
  // 最後の転送を終えて返ってきた際に、判定するため
  //
  m_vec.push_back(getLE(buf, PKT_ID_BYTES));

  // 生成したパケットを最初の宛先に送信
  AXFObjectName toName = getCntName(buf, cnt);
  if (send(toName, (AXFEvent_t) EVENT_LOOPBACK_TEST, (void *) buf, size) < 0) {
    m_log.write(AXFLOG_ERR, "fail send loopback");
    return ax::AXFACTOR_ERROR;
  }


  // 次のテストパケットを生成するために
  // タイマーを設定する

  // 1 から 5999 tick の期間を乱数で生成し、
  // 単発タイマーに設定する

  // タイマー満了時に、
  // エージングテスト開始用のイベント EVENT_STARTLOOPBAK_TEST が
  // 自身に送信され
  // イベントハンドラである本メソッドが再び呼び出される

  INT32_t sec = 0;
  INT32_t tick = rand() % TICK_PER_SEC;
  if (tick == 0)
    tick = 1;
  timeSpec ts = { sec, tick };
  if (startSingleShotTimer(ts, EVENT_STARTLOOPBACK_TEST, &m_timerId)
      != TIMER_SUCCESS) {
    m_log.write(AXFLOG_ERR, "fail start timer");
    return ax::AXFACTOR_ERROR;
  }
  return ax::AXFACTOR_SUCCESS;
}


// AXMTest::funcStopLoopbackTest
//   エージングテスト停止用のイベント EVENT_STOPLOOPBAK_TEST で呼び出される
//   イベントハンドラ
//
//   タイマーによるパケット生成を停止させ、テストを停止する
//   後処理をして結果を表示する
//
ax::actorFuncStatus AXMTest::funcStopLoopbackTest(const void *pParam,
                                                  int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcStopLoopbackTest()");

#ifdef USE_AXFTEST_COMMAND_COMPLOG
  if(m_isLoopback == true) {
    //テスト開始を設定
    AXMScenarioTest::getInstance()->setTestCase(AXMScenarioTest::TEST_STOPLB);
  }
#endif /* USE_AXFTEST_COMMAND_COMPLOG */

  // 次のパケット生成のためのタイマーが設定されいるか判定
  if (m_timerId) {

    // 次のパケット生成のためのタイマーが設定されいる場合

    // 設定されているタイマーを停止(キャンンセル)
    if (stopSingleShotTimer(m_timerId) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail stop timer");
      return ax::AXFACTOR_ERROR;
    }
    m_timerId = 0;

    // 2秒後に、再びこのメソッドが呼び出されるように
    // 単発タイマにイベントを設定
    //
    // 最後に生成したテストパケットが転送を繰り返している場合でも
    // 2秒後には転送を終了している事を想定
    //
    timeSpec ts = { 2, 0 };
    TimerId_t tid;
    startSingleShotTimer(ts, EVENT_STOPLOOPBACK_TEST, &tid);
    return ax::AXFACTOR_SUCCESS;
  }

  // この位置では
  // 次のパケット生成のためのタイマーが設定されいない状態
  // 最後に生成されたパケットの転送も終了している状態 (?)

  // エージングテストが開始されているか判定
  if (m_isLoopback) {
    // エージングテストが開始されている場合

    m_isLoopback = false;

    // 開始時に記録した時刻から動作した期間を算出して表示する
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
    AXFChrono::TimeSpec difftime = (getCurrentTime() - m_chronoStart).getCounter();
    int sec = difftime.sec;
#endif
    std::ostringstream oss;

    // 生成してきたパケットについて
    // パケット識別IDリスト中に、返ってこなかったパケットが
    // 残ってないか確認する
    if (m_vec.size() > 0) {
      oss << "remain packet " << m_vec.size();
      m_log.write(AXFLOG_ERR, oss.str());
      oss.str("");
      m_vec.clear();
    }

    // テストした回数と時間を表示
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
    oss << "loopbackCount=" << m_loopbackCount << "  " << sec << " sec";
#else
		oss << "loopbackCount=" << m_loopbackCount;
#endif
    m_log.write(AXFLOG_ERR, oss.str());
#ifdef USE_AXFTEST_COMMAND_COMPLOG
    AXMScenarioTest::getInstance()->writeLog(&m_log, AXMScenarioTest::RESULT_SUCCESS);
#endif /* USE_AXFTEST_COMMAND_COMPLOG */
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcStartLoopbackAll(const void *pParam,
                                                  int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcStartLoopbackAll()");

  for (int i = 0; i < NAMES_N; i++) {
    if (send(names[i], EVENT_STARTLOOPBACK_TEST, NULL, 0) < 0) {
      return ax::AXFACTOR_ERROR;
    }
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcStopLoopbackAll(const void *pParam, int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcStopLoopbackAll()");

  for (int i = 0; i < NAMES_N; i++) {
    if (send(names[i], EVENT_STOPLOOPBACK_TEST, NULL, 0) < 0) {
      return ax::AXFACTOR_ERROR;
    }
  }
  return ax::AXFACTOR_SUCCESS;
}

// アクタへ同時に複数のタイマを設定するテスト
ax::actorFuncStatus AXMTest::funcTimerTest(const void *pParam,
					   int size) {
  static TimerId_t ids[10];
  static int cnt = 0;

  if (!m_isTimerTest) {
    // テストコマンドによる初回の呼び出しの場合

    // 呼び出し回数のカウンタを0クリアし、現在時刻を表示
    cnt = 0;
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
    m_log.write(AXFLOG_NOTICE, "start " + getCurrentTime().getString());
#endif


    // 複数の Single Shot Timer をセット
    // 満了時は本メソッドをハンドラとして呼び出すようにイベントを指定

    // 1.5 sec
    INT32_t sec = 1;
    INT32_t tick = TICK_PER_SEC / 2;
    timeSpec ts = { sec, tick };

    if (startSingleShotTimer(ts, EVENT_TIMER_TEST, &ids[0]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startSingleShotTimer");
      return ax::AXFACTOR_ERROR;
    }

    // 2.5 sec
    ts.sec++;
    if (startSingleShotTimer(ts, EVENT_TIMER_TEST, &ids[1]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startSingleShotTimer");
      return ax::AXFACTOR_ERROR;
    }

    // 3.5 sec
    ts.sec++;
    if (startSingleShotTimer(ts, EVENT_TIMER_TEST, &ids[2]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startSingleShotTimer");
      return ax::AXFACTOR_ERROR;
    }

    // 4.5 sec
    ts.sec++;
    if (startSingleShotTimer(ts, EVENT_TIMER_TEST, &ids[3]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startSingleShotTimer");
      return ax::AXFACTOR_ERROR;
    }


    // 複数の Interval Timer をセット
    // 満了時は本メソッドをハンドラとして呼び出すようにイベントを指定

    // 1 , 2 , 3 , 4 , 5 , 6 sec
    ts.sec = 1;
    ts.tick = 0;
    if (startIntervalTimer(ts, EVENT_TIMER_TEST, &ids[4]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startIntervalTimer");
      return ax::AXFACTOR_ERROR;
    }

    // 2 , 4 , 6 sec
    ts.sec = 2;
    ts.tick = 0;
    if (startIntervalTimer(ts, EVENT_TIMER_TEST, &ids[5]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startIntervalTimer");
      return ax::AXFACTOR_ERROR;
    }
    
    // 3 , 6 sec
    ts.sec = 3;
    if (startIntervalTimer(ts, EVENT_TIMER_TEST, &ids[6]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startIntervalTimer");
      return ax::AXFACTOR_ERROR;
    }
    
    // 5 sec
    ts.sec = 5;
    if (startIntervalTimer(ts, EVENT_TIMER_TEST, &ids[7]) != TIMER_SUCCESS) {
      m_log.write(AXFLOG_ERR, "fail startIntervalTimer");
      return ax::AXFACTOR_ERROR;
    }

    // タイマテスト実行中フラグを設定
    m_isTimerTest = true;

  } else {
    // タイマ満了により呼び出された場合
		
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
    // 現在時刻を表示
    m_log.write(AXFLOG_NOTICE, "call " + getCurrentTime().getString());
#endif


    // 設定した複数のタイマが一通り満了した分の回数だけ
    // 本メソッドが呼び出されたか判定

    // Single Shot Timer 4
    // Interval Timer 6 + 3 + 2 + 1
    if (++cnt >= 4 + 6 + 3 + 2 + 1) {

      // Single Shot Timer は
      // 満了し破棄されている前提

      // Interval Timer を停止する

      if (stopIntervalTimer(ids[4]) != TIMER_SUCCESS) {
	m_log.write(AXFLOG_ERR, "fail stopIntervalTimer");
	return ax::AXFACTOR_ERROR;
      }
      if (stopIntervalTimer(ids[5]) != TIMER_SUCCESS) {
	m_log.write(AXFLOG_ERR, "fail stopIntervalTimer");
	return ax::AXFACTOR_ERROR;
      }
      if (stopIntervalTimer(ids[6]) != TIMER_SUCCESS) {
	m_log.write(AXFLOG_ERR, "fail stopIntervalTimer");
	return ax::AXFACTOR_ERROR;
      }
      if (stopIntervalTimer(ids[7]) != TIMER_SUCCESS) {
	m_log.write(AXFLOG_ERR, "fail stopIntervalTimer");
	return ax::AXFACTOR_ERROR;
      }

      // 停止した時の現在時刻を表示
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
      m_log.write(AXFLOG_NOTICE, "stop " + getCurrentTime().getString());
#endif

      // タイマテスト実行中フラグを解除
      m_isTimerTest = false;
    }
  }

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcWatchdogTimeoutTest(const void *pParam,
                                                     int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcWatchdogTimeoutTest()");

  while (m_watchdogLoop == true) {
    ;
  }

  return ax::AXFACTOR_SUCCESS;
}

#ifdef USE_AXFTEST_COMMAND
extern AXFObjectName nameAXTest;
extern AXFObjectName nameAXTest2;
extern AXFObjectName nameAXTest3;
extern AXFObjectName nameAXTest4;

ax::actorFuncStatus AXMTest::funcSampleScriptHandler1(const void *pParam,
                                                      int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcSampleScriptHandler1()");
  if (0 > send(nameAXTest4, EVENT_SAMPLE_SCRIPT_HANDLER2, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_SAMPLE_SCRIPT_HANDLER2");
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcSampleScriptHandler2(const void *pParam,
                                                      int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcSampleScriptHandler2()");
  if (0 > send(nameAXTest3, EVENT_SAMPLE_SCRIPT_HANDLER3, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_SAMPLE_SCRIPT_HANDLER3");
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcSampleScriptHandler3(const void *pParam,
                                                      int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcSampleScriptHandler3()");
  if (0 > send(nameAXTest2, EVENT_SAMPLE_SCRIPT_HANDLER4, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_SAMPLE_SCRIPT_HANDLER4");
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcSampleScriptHandler4(const void *pParam,
                                                      int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcSampleScriptHandler4()");
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMTest::funcSampleScriptHandler5(const void *pParam,
                                                      int size) {
  m_log.write(AXFLOG_INFO, "@AXMTest funcSampleScriptHandler5()");
  return ax::AXFACTOR_ERROR;
}
#endif /* USE_AXFTEST_COMMAND */

#ifdef USE_AXFTEST_COMMAND_COMPLOG
ax::actorFuncStatus AXMTest::funcScenarioTestIspTimeout(const void *pParam,
    int size) {
  m_log.write(AXFLOG_SCENARIO, "@AXMTest funcScenarioIspTestTimeout()");

  AXMScenarioTest::getInstance()->writeLog(&m_log,
      AXMScenarioTest::RESULT_FAILED, AXMScenarioTest::E_TIMEOUT);
  return ax::AXFACTOR_SUCCESS;
}
ax::actorFuncStatus AXMTest::funcScenarioTestAxTimeout(const void *pParam,
    int size) {
  m_log.write(AXFLOG_SCENARIO, "@AXMTest funcScenarioTestAxTimeout()");

  AXMScenarioTest::getInstance()->writeLog(&m_log,
      AXMScenarioTest::RESULT_FAILED, AXMScenarioTest::E_TIMEOUT);
  return ax::AXFACTOR_SUCCESS;
}
#endif /* USE_AXFTEST_COMMAND_COMPLOG */
