// =====================================================================
//  $Id: DaqEventAction.cc,v 1.1 2006/02/15 07:04:51 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: DaqEventAction.cc,v $
//  Revision 1.1  2006/02/15 07:04:51  goiwai
//  ドキュメント用に最も簡単な例題ソフトウェアDAQプログラムを作りました。
//
// =====================================================================
#include "TEventManager.hh"
#include "TEvent.hh"
#include "DaqEventAction.hh"

#include "TSoftwareInterruptRegisterModule.hh"
#include "TReadoutBook.hh"
#include "TCrate.hh"
#include "TOutputObjectFile.hh"
#include "TRunManager.hh"
#include "TRandomFlat.hh"
#include "DaqRunAction.hh"

DaqEventAction::DaqEventAction()
  : TEventAction()
{;}

DaqEventAction::~DaqEventAction()
{;}

TReadoutList* DaqEventAction::WaitTrigger()
{
  // トリガー待ち受け動作の定義

  TSoftwareInterruptRegisterModule* interrupt =
    (TSoftwareInterruptRegisterModule*)(theCrate->GetModule("INTERRUPT"));

  enum { NOSIGNAL = 0x0000, ADC = 0x0001, SCALER = 0x0002, BOTH = 0x0003 };

  // インタラプトレジスターをポーリングで見張る
  while (1) {
    Tint bit = interrupt->ReadInterruptRegister();

    // ADCまたは両方のフラグが立っていればADCトリガー
    if (bit == ADC || bit == BOTH) {
      return theReadoutBook->GetReadoutList("ADC TRIGGER");

    // SCALERのフラグが立っていればSCALERトリガー
    } else if (bit == SCALER) {
      return theReadoutBook->GetReadoutList("SCALER TRIGGER");
    } else {
      continue;
    }
  }
}

Tvoid DaqEventAction::AtFirst( TEvent& anEvent )
{
  TSoftwareInterruptRegisterModule* interrupt =
    (TSoftwareInterruptRegisterModule*)(theCrate->GetModule("INTERRUPT"));

  // イベントループ開始時にトリガーレートを適当に設定(1-10Hz)
  interrupt->SetFrequency(TRandomFlat::shootInt(1,10));

  // マスク処理を行い8bit中の上位6bitはフラグが立たないようにする
  // つまりチャンネル0(ADC)か1(SCALER)のみ有効
  interrupt->SetInterruptMaskRegister(0x00fc);

  return;
}

Tvoid DaqEventAction::AtLast( TEvent& anEvent )
{
  DaqRunAction* action =
    (DaqRunAction*)(theRunManager->GetRunAction());
  TOutputObjectFile* ofile = action->GetOutputFile();

  // イベント毎に取得データを記録する
  TDataRecord record = anEvent.GetDataRecord();
  ofile->Write(record);

  // ADCトリガーならADCを更新する
  if (record.GetID() == "ADC TRIGGER") {
    theCrate->GetModule("ADC")->Update();

  // SCALERトリガーならSCALERを更新する
  } else if (record.GetID() == "SCALER TRIGGER") {
    theCrate->GetModule("SCALER")->Update();
  }

  // TIMER,CLOCK,INTERRUPTは毎イベント更新する
  theCrate->GetModule("TIMER")->Update();
  theCrate->GetModule("CLOCK")->Update();
  theCrate->GetModule("INTERRUPT")->Clear();

  return;
}
