1580 lines
50 KiB
C++
1580 lines
50 KiB
C++
/*
|
|
* Osci.cpp
|
|
* DRS oscilloscope main class
|
|
* $Id: Osci.cpp 22326 2016-10-10 14:21:29Z ritt $
|
|
*/
|
|
|
|
#include "DRSOscInc.h"
|
|
#include "rb.h"
|
|
|
|
#ifndef _MSC_VER
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
int g_rbh;
|
|
|
|
#define RB_SIZE (1024*1024*4) // 4 MB fits 60 waveforms for four boards
|
|
|
|
void GetTimeStamp(TIMESTAMP &ts);
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
Osci::Osci(double samplingSpeed, bool mthread)
|
|
{
|
|
m_drs = NULL;
|
|
m_thread = NULL;
|
|
m_running = false;
|
|
m_single = false;
|
|
m_armed = false;
|
|
m_samplingSpeed = samplingSpeed;
|
|
m_triggerCell[0] = 0;
|
|
m_writeSR[0] = 0;
|
|
m_waveDepth = 1024;
|
|
m_trgDelay = 0;
|
|
for (int i=0 ; i<4 ; i++)
|
|
m_trgLevel[i] = 0;
|
|
for (int b=0 ; b<MAX_N_BOARDS ; b++) {
|
|
m_trgNegative[b] = false;
|
|
m_trgMode[b] = TM_AUTO;
|
|
m_trgConfig[b] = 0;
|
|
m_refClk[b] = false;
|
|
for (int i=0 ; i<4 ; i++)
|
|
m_chnOn[b][i] = false;
|
|
}
|
|
m_clkOn = false;
|
|
m_calibOn = false;
|
|
m_evSerial = 1;
|
|
m_calibrated = true;
|
|
m_calibrated2 = true;
|
|
m_tcalon = true;
|
|
m_rotated = true;
|
|
m_nDRS = 0;
|
|
m_board = 0;
|
|
m_chip = 0;
|
|
m_chnOffset = 0;
|
|
m_chnSection = 0;
|
|
m_spikeRemoval = false;
|
|
m_inputRange = 0;
|
|
m_skipDisplay = false;
|
|
m_multiBoard = false;
|
|
m_debugMsg[0] = 0;
|
|
|
|
ScanBoards();
|
|
SelectBoard(0);
|
|
SelectChannel(0, 0);
|
|
|
|
if (mthread) {
|
|
rb_create(RB_SIZE, 4*MAX_N_BOARDS*(9*1024*2+64), &g_rbh);
|
|
m_thread = new OsciThread(this);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
Osci::~Osci()
|
|
{
|
|
if (m_thread) {
|
|
m_thread->StopThread();
|
|
wxThread::Sleep(100);
|
|
}
|
|
if (g_rbh)
|
|
rb_delete(g_rbh);
|
|
delete m_drs;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::StopThread(void)
|
|
{
|
|
if (m_thread) {
|
|
do {
|
|
m_thread->StopThread();
|
|
wxThread::Sleep(100);
|
|
} while (!m_thread->IsFinished());
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void GetTimeStamp(TIMESTAMP &ts)
|
|
{
|
|
#ifdef _MSC_VER
|
|
SYSTEMTIME t;
|
|
static unsigned int ofs = 0;
|
|
|
|
GetLocalTime(&t);
|
|
if (ofs == 0)
|
|
ofs = timeGetTime() - t.wMilliseconds;
|
|
ts.Year = t.wYear;
|
|
ts.Month = t.wMonth;
|
|
ts.Day = t.wDay;
|
|
ts.Hour = t.wHour;
|
|
ts.Minute = t.wMinute;
|
|
ts.Second = t.wSecond;
|
|
ts.Milliseconds = (timeGetTime() - ofs) % 1000;
|
|
#else
|
|
struct timeval t;
|
|
struct tm *lt;
|
|
time_t now;
|
|
|
|
gettimeofday(&t, NULL);
|
|
time(&now);
|
|
lt = localtime(&now);
|
|
|
|
ts.Year = lt->tm_year+1900;
|
|
ts.Month = lt->tm_mon+1;
|
|
ts.Day = lt->tm_mday;
|
|
ts.Hour = lt->tm_hour;
|
|
ts.Minute = lt->tm_min;
|
|
ts.Second = lt->tm_sec;
|
|
ts.Milliseconds = t.tv_usec/1000;
|
|
#endif /* OS_UNIX */
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
int Osci::ScanBoards()
|
|
{
|
|
/* pause readout thread if present */
|
|
if (m_thread)
|
|
m_thread->Enable(false);
|
|
|
|
if (m_drs)
|
|
delete m_drs;
|
|
|
|
m_drs = new DRS();
|
|
m_drs->SortBoards();
|
|
m_nDRS = m_drs->GetNumberOfBoards();
|
|
m_board = 0;
|
|
|
|
for (int i=0 ; i< m_nDRS ; i++) {
|
|
DRSBoard *b = m_drs->GetBoard(i);
|
|
b->Init();
|
|
if (b->GetBoardType() == 3) { // DRS2 board
|
|
b->SetDominoMode(1);
|
|
b->EnableTrigger(1, 0); // fast trigger
|
|
if (m_samplingSpeed > 2)
|
|
m_samplingSpeed = 2;
|
|
b->SetFrequency(m_samplingSpeed, true);
|
|
m_samplingSpeed = b->GetNominalFrequency();
|
|
b->SetNumberOfChannels(10);
|
|
#ifdef _MSC_VER
|
|
b->SetCalibrationDirectory("C:/experiment/calibrations");
|
|
#else
|
|
b->SetCalibrationDirectory("/home/meg/meg/online/calibrations");
|
|
#endif
|
|
|
|
if (i == 0)
|
|
printf("Reading calibration for sampling speed %lg GSPS\n", m_samplingSpeed);
|
|
|
|
if (!b->GetResponseCalibration()->ReadCalibration(0) ||
|
|
!b->GetResponseCalibration()->ReadCalibration(1)) {
|
|
wxString str;
|
|
|
|
str.Printf(wxT("Cannot read calibration for %1.1lf GSPS VME board slot %2d %s, serial #%d"),
|
|
m_samplingSpeed,
|
|
(b->GetSlotNumber() >> 1)+2,
|
|
((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower",
|
|
b->GetBoardSerialNumber());
|
|
|
|
wxMessageBox(str, wxT("DRS Oscilloscope Error"), wxOK | wxICON_STOP, NULL);
|
|
} else {
|
|
printf("Calibration read for VME board slot %2d %s, serial #%04d\n",
|
|
(b->GetSlotNumber() >> 1)+2,
|
|
((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower",
|
|
b->GetBoardSerialNumber());
|
|
}
|
|
|
|
} else { // DRS4 board
|
|
|
|
/* obtain default sampling speed from calibration of first board */
|
|
if (i == 0)
|
|
m_samplingSpeed = b->GetCalibratedFrequency();
|
|
|
|
b->SetFrequency(m_samplingSpeed, true);
|
|
m_samplingSpeed = b->GetNominalFrequency();
|
|
if (b->GetTransport() == TR_USB2)
|
|
b->SetChannelConfig(0, 8, 8);
|
|
else
|
|
b->SetChannelConfig(7, 8, 8);
|
|
b->SetDecimation(0);
|
|
b->SetDominoMode(1);
|
|
b->SetReadoutMode(1);
|
|
b->SetDominoActive(1);
|
|
if (b->GetBoardType() == 5 || b->GetBoardType() == 7 || b->GetBoardType() == 8 || b->GetBoardType() == 9) {
|
|
b->SetTranspMode(1); // Evaluation board with build-in trigger
|
|
b->EnableTrigger(0, 1); // Enable analog trigger
|
|
b->SetTriggerConfig(1<<0); // on CH0
|
|
} else if (b->GetBoardType() == 6) {
|
|
b->SetTranspMode(0); // VPC Mezzanine board
|
|
b->EnableTrigger(0, 0); // Disable analog trigger
|
|
}
|
|
b->SetRefclk(0);
|
|
b->SetFrequency(m_samplingSpeed, true);
|
|
b->EnableAcal(0, 0);
|
|
b->EnableTcal(0, 0);
|
|
b->StartDomino();
|
|
}
|
|
}
|
|
|
|
/* resume readout thread if present */
|
|
if (m_thread)
|
|
m_thread->Enable(true);
|
|
|
|
return m_nDRS;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::CheckTimingCalibration()
|
|
{
|
|
for (int i=0 ; i< m_nDRS ; i++) {
|
|
DRSBoard *b = m_drs->GetBoard(i);
|
|
if (b->GetDRSType() == 4) {
|
|
|
|
if (!b->IsVoltageCalibrationValid()) {
|
|
wxString str;
|
|
|
|
if (b->GetTransport() != TR_VME) {
|
|
str.Printf(wxT("Board on USB%d has invalid voltage calibration\nOnly raw data will be displayed"),
|
|
b->GetSlotNumber());
|
|
} else {
|
|
str.Printf(wxT("VME board in slot %2d %s has invalid voltage calibration\nOnly raw data will be displayed"),
|
|
(b->GetSlotNumber() >> 1)+2,
|
|
((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower");
|
|
}
|
|
wxMessageBox(str, wxT("DRS Oscilloscope Warning"), wxOK | wxICON_EXCLAMATION);
|
|
} else {
|
|
if (!b->IsTimingCalibrationValid()) {
|
|
wxString str;
|
|
|
|
if (b->GetTransport() != TR_VME) {
|
|
if (b->GetCalibratedFrequency() == -1)
|
|
str.Printf(wxT("Board on USB%d has been timing calibrated with an old method. You must redo the timing calibration to obtain precise timing results."), b->GetSlotNumber());
|
|
else
|
|
str.Printf(wxT("Board on USB%d has been timing calibrated at %1.4lg GSPS. You must redo the timing calibration at %1.4lg GSPS to obtain precise timing results."),
|
|
b->GetSlotNumber(), b->GetCalibratedFrequency(), m_samplingSpeed);
|
|
} else {
|
|
str.Printf(wxT("VME board in slot %2d %s has been timing calibrated at %1.4lg GSPS. You must redo the timing calibration at %1.4lg GSPS to obtain precise timing results."),
|
|
(b->GetSlotNumber() >> 1)+2,
|
|
((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower",
|
|
b->GetCalibratedFrequency(), b->GetNominalFrequency());
|
|
}
|
|
wxMessageBox(str, wxT("DRS Oscilloscope Warning"), wxOK | wxICON_EXCLAMATION);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SelectBoard(int board)
|
|
{
|
|
if (board >= m_nDRS)
|
|
return;
|
|
|
|
/* pause readout thread if present */
|
|
if (m_thread)
|
|
m_thread->Enable(false);
|
|
|
|
m_board = board;
|
|
|
|
if (m_thread)
|
|
DrainEvents();
|
|
|
|
/* resume readout thread if present */
|
|
if (m_thread)
|
|
m_thread->Enable(true);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SelectChannel(int firstChannel, int chnSection)
|
|
{
|
|
if (m_drs->GetNumberOfBoards() == 0)
|
|
return;
|
|
|
|
/* pause readout thread if present */
|
|
if (m_thread)
|
|
m_thread->Enable(false);
|
|
|
|
for (int bi=0 ; bi < m_nDRS ; bi++) {
|
|
DRSBoard *b = m_drs->GetBoard(bi);
|
|
|
|
/* stop drs_readout state machine to be ready for configuration change */
|
|
if (b->IsBusy()) {
|
|
b->SoftTrigger();
|
|
for (int i=0 ; i<10 && b->IsBusy() ; i++)
|
|
wxMilliSleep(10);
|
|
}
|
|
|
|
if (b->GetBoardType() == 6 && b->GetTransport() == TR_USB2) {
|
|
if (firstChannel == 0 || firstChannel == 2) {
|
|
if (chnSection == 0)
|
|
b->SetChannelConfig(1, 8, 8);
|
|
else
|
|
b->SetChannelConfig(0, 8, 8);
|
|
} else {
|
|
if (chnSection == 0)
|
|
b->SetChannelConfig(3, 8, 8);
|
|
else
|
|
b->SetChannelConfig(2, 8, 8);
|
|
}
|
|
m_chip = firstChannel;
|
|
m_chnOffset = 0;
|
|
m_chnSection = chnSection;
|
|
} else {
|
|
m_chip = firstChannel;
|
|
m_chnOffset = chnSection;
|
|
m_chnSection = chnSection;
|
|
|
|
if (b->GetBoardType() == 3) {
|
|
m_chip = firstChannel / 2;
|
|
m_chnOffset = (firstChannel % 2)* 4;
|
|
}
|
|
|
|
if (b->GetBoardType() == 5 || b->GetBoardType() == 7 || b->GetBoardType() == 8 || b->GetBoardType() == 9) {
|
|
if (chnSection == 2)
|
|
b->SetChannelConfig(0, 8, 4);
|
|
else
|
|
b->SetChannelConfig(0, 8, 8);
|
|
} else {
|
|
if (chnSection == 2)
|
|
b->SetChannelConfig(7, 8, 4);
|
|
else
|
|
b->SetChannelConfig(7, 8, 8);
|
|
}
|
|
}
|
|
|
|
/* resume readout thread if present */
|
|
if (m_thread)
|
|
m_thread->Enable(true);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetMultiBoard(bool flag)
|
|
{
|
|
m_multiBoard = flag;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
OsciThread::OsciThread(Osci *o) : wxThread()
|
|
{
|
|
m_osci = o;
|
|
m_enabled = false;
|
|
m_finished = false;
|
|
m_active = false;
|
|
m_stopThread = false;
|
|
Create();
|
|
Run();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void OsciThread::Enable(bool flag)
|
|
{
|
|
m_enabled = flag;
|
|
if (!flag)
|
|
while (m_active)
|
|
wxThread::Sleep(10);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void OsciThread::StopThread()
|
|
{
|
|
m_stopThread = true;
|
|
while (!m_finished)
|
|
wxThread::Sleep(10);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool OsciThread::IsIdle()
|
|
{
|
|
if (m_osci->IsRunning() && m_sw1.Time() > 1000)
|
|
return true;
|
|
|
|
if (m_osci->IsSingle() && m_osci->IsArmed() && m_sw1.Time() > 1000)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void OsciThread::ResetSW()
|
|
{
|
|
m_sw1.Start();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void *OsciThread::Entry()
|
|
{
|
|
int size, index, status, n, m;
|
|
unsigned char *pdata;
|
|
unsigned short *p;
|
|
bool autoTriggered;
|
|
DRSBoard *b;
|
|
TIMESTAMP ts;
|
|
bool skip_event;
|
|
time_t lastTempRead = 0;
|
|
|
|
n = m = 0;
|
|
autoTriggered = false;
|
|
do {
|
|
if (m_osci->GetDRS()->GetNumberOfBoards() > 0 && m_enabled) {
|
|
m_active = true;
|
|
if (m_osci->HasTriggered()) {
|
|
|
|
skip_event = false;
|
|
n = 0;
|
|
if (!autoTriggered)
|
|
m_sw1.Start(); // we got a real trigger
|
|
autoTriggered = false;
|
|
|
|
// wait for space in ring buffer
|
|
do {
|
|
status = rb_get_wp(g_rbh, (void **)&pdata, 100);
|
|
if (status == RB_SUCCESS) {
|
|
// put number of boards into ring buffer
|
|
p = (unsigned short *)pdata;
|
|
*p++ = m_osci->IsMultiBoard() ? m_osci->GetDRS()->GetNumberOfBoards() : 1;
|
|
|
|
for (index = 0 ; index < m_osci->GetDRS()->GetNumberOfBoards() ; index++) {
|
|
|
|
b = m_osci->GetBoard(index);
|
|
if (!m_osci->IsMultiBoard() && m_osci->GetCurrentBoard() != b)
|
|
continue;
|
|
|
|
// abort event readout if slave board has not triggered
|
|
if (m_osci->IsMultiBoard())
|
|
if (index > 0)
|
|
if (b->IsBusy())
|
|
skip_event = true;
|
|
|
|
if (skip_event)
|
|
break;
|
|
|
|
// transfer waveforms
|
|
b->TransferWaves((unsigned char *)p);
|
|
size = b->GetWaveformBufferSize();
|
|
|
|
p += size/sizeof(unsigned short);
|
|
*p++ = b->GetStopCell(0);
|
|
*p++ = b->GetStopWSR(0);
|
|
*p++ = (unsigned short)b->GetBoardSerialNumber();
|
|
}
|
|
|
|
// restart boards in inverted order (master last)
|
|
for (index = m_osci->GetDRS()->GetNumberOfBoards()-1 ; index>=0 ; index--) {
|
|
b = m_osci->GetBoard(index);
|
|
if (!m_osci->IsMultiBoard() && m_osci->GetCurrentBoard() != b)
|
|
continue;
|
|
|
|
if (m_osci->IsRunning()) {
|
|
// only if not in multi buffer mode
|
|
if (!b->IsMultiBuffer())
|
|
b->StartDomino();
|
|
}
|
|
}
|
|
|
|
// in single mode, just clear armed flag
|
|
if (m_osci->IsSingle())
|
|
m_osci->SetArmed(false);
|
|
|
|
if (skip_event)
|
|
break;
|
|
|
|
// add timestamp
|
|
GetTimeStamp(ts);
|
|
memcpy(p, &ts, sizeof(ts));
|
|
p += sizeof(ts)/sizeof(unsigned short);
|
|
size = (unsigned char*)p - pdata;
|
|
|
|
// commit data to ring buffer
|
|
rb_increment_wp(g_rbh, size);
|
|
} else
|
|
wxThread::Sleep(10);
|
|
|
|
if (m_stopThread)
|
|
break;
|
|
|
|
} while (status != RB_SUCCESS && !TestDestroy());
|
|
|
|
#ifndef _MSC_VER // Needed for Linux only, otherwise GUI freezes
|
|
if (m++ % 10 == 0)
|
|
wxThread::Yield();
|
|
#endif
|
|
|
|
} else {
|
|
if (m_osci->GetTriggerMode() == TM_AUTO && m_osci->IsRunning() &&
|
|
m_sw1.Time() > 1000) {
|
|
if (m_sw2.Time() > 300) {
|
|
wxThread::Sleep(30); // sleep 3 times a second a bit to test for real trigger
|
|
m_sw2.Start();
|
|
}
|
|
if (!m_osci->HasTriggered()) {
|
|
m_osci->SingleTrigger();
|
|
autoTriggered = true;
|
|
}
|
|
} else {
|
|
n++;
|
|
// sleep once in a while to save CPU
|
|
if (n == 100) {
|
|
n = 0;
|
|
wxThread::Sleep(100);
|
|
} else
|
|
wxThread::Yield();
|
|
}
|
|
}
|
|
} else {
|
|
wxThread::Sleep(10);
|
|
m_active = false;
|
|
}
|
|
|
|
// read temperature once every second
|
|
time_t now;
|
|
time(&now);
|
|
if (now > lastTempRead) {
|
|
lastTempRead = now;
|
|
for (int i=0 ; i<m_osci->GetDRS()->GetNumberOfBoards() ; i++) {
|
|
b = m_osci->GetBoard(i);
|
|
b->ReadTemperature();
|
|
}
|
|
}
|
|
|
|
} while (!m_stopThread);
|
|
|
|
m_finished = true;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetRunning(bool flag)
|
|
{
|
|
m_running = flag;
|
|
if (m_running)
|
|
Start();
|
|
else {
|
|
Stop();
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
DrainEvents();
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::Enable(bool flag)
|
|
{
|
|
if (m_thread)
|
|
m_thread->Enable(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::Start()
|
|
{
|
|
/* start domino wave */
|
|
if (m_multiBoard) {
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
m_drs->GetBoard(i)->StartDomino();
|
|
} else if (m_drs->GetNumberOfBoards())
|
|
m_drs->GetBoard(m_board)->StartDomino();
|
|
|
|
m_armed = true;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::Stop()
|
|
{
|
|
/* stop domino wave */
|
|
if (m_multiBoard) {
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
m_drs->GetBoard(i)->SoftTrigger();
|
|
} else if (m_drs->GetNumberOfBoards())
|
|
m_drs->GetBoard(m_board)->SoftTrigger();
|
|
m_armed = false;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::DrainEvents()
|
|
{
|
|
while (HasNewEvent())
|
|
ReadWaveforms();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetSingle(bool flag)
|
|
{
|
|
m_single = flag;
|
|
if (m_thread)
|
|
m_thread->ResetSW();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SingleTrigger()
|
|
{
|
|
if (m_multiBoard) {
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
m_drs->GetBoard(i)->SoftTrigger();
|
|
} else if (m_drs->GetNumberOfBoards())
|
|
m_drs->GetBoard(m_board)->SoftTrigger();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool Osci::HasNewEvent()
|
|
{
|
|
int n;
|
|
|
|
if (m_drs->GetNumberOfBoards() > 0) {
|
|
if (m_thread) {
|
|
rb_get_buffer_level(g_rbh, &n);
|
|
return n > 0;
|
|
} else {
|
|
if (m_armed && m_drs->GetBoard(m_board)->IsBusy() == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
} else
|
|
return m_running;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool Osci::HasTriggered()
|
|
{
|
|
int i;
|
|
|
|
if (m_drs->GetNumberOfBoards() > 0) {
|
|
if (m_multiBoard) // only first board can trigger
|
|
i = 0;
|
|
else
|
|
i = m_board;
|
|
if (m_running)
|
|
return m_drs->GetBoard(i)->IsEventAvailable() > 0;
|
|
if (m_single && m_armed)
|
|
return m_drs->GetBoard(i)->IsEventAvailable() > 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool Osci::IsIdle()
|
|
{
|
|
if (m_thread)
|
|
return m_thread->IsIdle();
|
|
return false;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::ReadWaveforms()
|
|
{
|
|
unsigned char *pdata;
|
|
unsigned short *p;
|
|
int size = 0;
|
|
DRSBoard * b;
|
|
|
|
m_skipDisplay = false;
|
|
m_armed = false;
|
|
m_nBoards = 1;
|
|
|
|
if (m_drs->GetNumberOfBoards() == 0) {
|
|
for (int w=0 ; w<4 ; w++)
|
|
for (int i=0 ; i<GetWaveformDepth(w) ; i++) {
|
|
m_waveform[0][w][i] = sin(i/m_samplingSpeed/10*M_PI+w*M_PI/4)*100;
|
|
m_waveform[0][w][i] += ((double)rand()/RAND_MAX-0.5)*5;
|
|
m_time[0][w][i] = 1/m_samplingSpeed*i;
|
|
}
|
|
m_waveDepth = kNumberOfBins;
|
|
GetTimeStamp(m_evTimestamp);
|
|
} else {
|
|
int ofs = m_chnOffset;
|
|
int chip = m_chip;
|
|
|
|
if (m_drs->GetBoard(m_board)->GetBoardType() == 3) {
|
|
// DRS2 Mezzanine Board 1
|
|
m_drs->GetBoard(m_board)->TransferWaves();
|
|
int tc = m_drs->GetBoard(m_board)->GetTriggerCell(chip);
|
|
|
|
m_drs->GetBoard(m_board)->GetTime(chip, 0, m_samplingSpeed, tc, m_time[0][0], m_tcalon, m_rotated);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 0+ofs, m_waveform[0][0], m_calibrated, tc, !m_rotated);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 1+ofs, m_waveform[0][1], m_calibrated, tc, !m_rotated);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 2+ofs, m_waveform[0][2], m_calibrated, tc, !m_rotated);
|
|
if (m_clkOn)
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 9, m_waveform[0][3], m_calibrated, tc, !m_rotated);
|
|
else
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 3+ofs, m_waveform[0][3], m_calibrated, tc, !m_rotated);
|
|
} else if (m_drs->GetBoard(m_board)->GetBoardType() == 5 || m_drs->GetBoard(m_board)->GetBoardType() == 7 ||
|
|
m_drs->GetBoard(m_board)->GetBoardType() == 8 || m_drs->GetBoard(m_board)->GetBoardType() == 9) {
|
|
|
|
// DRS4 Evaluation Boards 1.1 + 3.0 + 4.0
|
|
if (m_thread) {
|
|
// get waveforms from ring buffer
|
|
if (rb_get_rp(g_rbh, (void **)&pdata, 0) != RB_SUCCESS)
|
|
return;
|
|
|
|
// transfer waveforms to buffer
|
|
size = m_drs->GetBoard(m_board)->GetWaveformBufferSize();
|
|
p = (unsigned short *)pdata;
|
|
m_nBoards = *p++; // number of boards
|
|
|
|
for (int i=0 ; i<m_nBoards ; i++) {
|
|
memcpy(m_wavebuffer[i], p, size);
|
|
p += size/sizeof(unsigned short);
|
|
m_triggerCell[i] = *p++;
|
|
m_writeSR[i] = *p++;
|
|
m_boardSerial[i] = *p++;
|
|
}
|
|
|
|
// transfer timestamp
|
|
memcpy(&m_evTimestamp, p, sizeof(m_evTimestamp));
|
|
p += sizeof(TIMESTAMP)/sizeof(unsigned short);
|
|
size = (unsigned char*)p - pdata;
|
|
|
|
// free space in ring buffer
|
|
rb_increment_rp(g_rbh, size);
|
|
} else {
|
|
// get waveforms directly from device
|
|
m_drs->GetBoard(m_board)->TransferWaves(m_wavebuffer[0], 0, 8);
|
|
m_triggerCell[0] = m_drs->GetBoard(m_board)->GetStopCell(chip);
|
|
m_writeSR[0] = m_drs->GetBoard(m_board)->GetStopWSR(chip);
|
|
GetTimeStamp(m_evTimestamp);
|
|
}
|
|
|
|
for (int i=0 ; i<m_nBoards ; i++) {
|
|
if (m_nBoards > 1)
|
|
b = m_drs->GetBoard(i);
|
|
else
|
|
b = m_drs->GetBoard(m_board);
|
|
|
|
// obtain time arrays
|
|
m_waveDepth = b->GetChannelDepth();
|
|
|
|
for (int w=0 ; w<4 ; w++)
|
|
b->GetTime(0, w*2, m_triggerCell[i], m_time[i][w], m_tcalon, m_rotated);
|
|
|
|
if (m_clkOn && GetWaveformDepth(0) > kNumberOfBins) {
|
|
for (int j=0 ; j<kNumberOfBins ; j++)
|
|
m_timeClk[i][j] = m_time[i][0][j] + GetWaveformLength()/2;
|
|
} else {
|
|
for (int j=0 ; j<kNumberOfBins ; j++)
|
|
m_timeClk[i][j] = m_time[i][0][j];
|
|
}
|
|
|
|
// decode and calibrate waveforms from buffer
|
|
if (b->GetChannelCascading() == 2) {
|
|
b->GetWave(m_wavebuffer[i], 0, 0, m_waveform[i][0], m_calibrated, m_triggerCell[i], m_writeSR[i], !m_rotated, 0, m_calibrated2);
|
|
b->GetWave(m_wavebuffer[i], 0, 1, m_waveform[i][1], m_calibrated, m_triggerCell[i], m_writeSR[i], !m_rotated, 0, m_calibrated2);
|
|
b->GetWave(m_wavebuffer[i], 0, 2, m_waveform[i][2], m_calibrated, m_triggerCell[i], m_writeSR[i], !m_rotated, 0, m_calibrated2);
|
|
if (m_clkOn && b->GetBoardType() < 9)
|
|
b->GetWave(m_wavebuffer[i], 0, 8, m_waveform[i][3], m_calibrated, m_triggerCell[i], 0, !m_rotated);
|
|
else
|
|
b->GetWave(m_wavebuffer[i], 0, 3, m_waveform[i][3], m_calibrated, m_triggerCell[i], m_writeSR[i], !m_rotated, 0, m_calibrated2);
|
|
if (m_spikeRemoval)
|
|
RemoveSpikes(i, true);
|
|
} else {
|
|
b->GetWave(m_wavebuffer[i], 0, 0+ofs, m_waveform[i][0], m_calibrated, m_triggerCell[i], 0, !m_rotated, 0, m_calibrated2);
|
|
b->GetWave(m_wavebuffer[i], 0, 2+ofs, m_waveform[i][1], m_calibrated, m_triggerCell[i], 0, !m_rotated, 0, m_calibrated2);
|
|
b->GetWave(m_wavebuffer[i], 0, 4+ofs, m_waveform[i][2], m_calibrated, m_triggerCell[i], 0, !m_rotated, 0, m_calibrated2);
|
|
if (m_clkOn && b->GetBoardType() < 9)
|
|
b->GetWave(m_wavebuffer[i], 0, 8, m_waveform[i][3], m_calibrated, m_triggerCell[i], 0, !m_rotated);
|
|
else
|
|
b->GetWave(m_wavebuffer[i], 0, 6+ofs, m_waveform[i][3], m_calibrated, m_triggerCell[i], 0, !m_rotated, 0, m_calibrated2);
|
|
|
|
if (m_spikeRemoval)
|
|
RemoveSpikes(i, false);
|
|
}
|
|
|
|
// extrapolate the first two samples (are noisy)
|
|
for (int j=0 ; j<4 ; j++) {
|
|
m_waveform[i][j][1] = 2*m_waveform[i][j][2] - m_waveform[i][j][3];
|
|
m_waveform[i][j][0] = 2*m_waveform[i][j][1] - m_waveform[i][j][2];
|
|
}
|
|
|
|
}
|
|
} else if (m_drs->GetBoard(m_board)->GetBoardType() == 6) {
|
|
// DRS4 Mezzanine Board 1
|
|
m_drs->GetBoard(m_board)->TransferWaves(0, 8);
|
|
m_triggerCell[0] = m_drs->GetBoard(m_board)->GetStopCell(chip);
|
|
m_writeSR[0] = m_drs->GetBoard(m_board)->GetStopWSR(chip);
|
|
m_waveDepth = m_drs->GetBoard(m_board)->GetChannelDepth();
|
|
|
|
m_drs->GetBoard(m_board)->GetTime(chip, 0, m_samplingSpeed, m_triggerCell[0], m_time[0][0], m_tcalon, m_rotated);
|
|
if (m_clkOn && GetWaveformDepth(0) > kNumberOfBins) {
|
|
for (int i=0 ; i<kNumberOfBins ; i++)
|
|
m_timeClk[0][i] = m_time[0][0][i] + GetWaveformLength()/2;
|
|
} else {
|
|
for (int i=0 ; i<kNumberOfBins ; i++)
|
|
m_timeClk[0][i] = m_time[0][0][i];
|
|
}
|
|
|
|
if (m_drs->GetBoard(m_board)->GetChannelCascading() == 2) {
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 0, m_waveform[0][0], m_calibrated, m_triggerCell[0], m_writeSR[0], !m_rotated, 0, m_calibrated2);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 1, m_waveform[0][1], m_calibrated, m_triggerCell[0], m_writeSR[0], !m_rotated, 0, m_calibrated2);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 2, m_waveform[0][2], m_calibrated, m_triggerCell[0], m_writeSR[0], !m_rotated, 0, m_calibrated2);
|
|
if (m_clkOn)
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 8, m_waveform[0][3], m_calibrated, m_triggerCell[0], m_writeSR[0], !m_rotated);
|
|
else {
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 3, m_waveform[0][3], m_calibrated, m_triggerCell[0], m_writeSR[0], !m_rotated, 0, m_calibrated2);
|
|
if (m_spikeRemoval)
|
|
RemoveSpikes(0, true);
|
|
}
|
|
} else {
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 0+ofs, m_waveform[0][0], m_calibrated, m_triggerCell[0], 0, !m_rotated, 0, m_calibrated2);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 2+ofs, m_waveform[0][1], m_calibrated, m_triggerCell[0], 0, !m_rotated, 0, m_calibrated2);
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 4+ofs, m_waveform[0][2], m_calibrated, m_triggerCell[0], 0, !m_rotated, 0, m_calibrated2);
|
|
if (m_clkOn)
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 8, m_waveform[0][3], m_calibrated, m_triggerCell[0], 0, !m_rotated);
|
|
else {
|
|
m_drs->GetBoard(m_board)->GetWave(chip, 6+ofs, m_waveform[0][3], m_calibrated, m_triggerCell[0], 0, !m_rotated, 0, m_calibrated2);
|
|
if (m_spikeRemoval)
|
|
RemoveSpikes(0, false);
|
|
}
|
|
}
|
|
|
|
/* extrapolate the first two samples (are noisy) */
|
|
for (int i=0 ; i<4 ; i++) {
|
|
m_waveform[0][i][1] = 2*m_waveform[0][i][2] - m_waveform[0][i][3];
|
|
m_waveform[0][i][0] = 2*m_waveform[0][i][1] - m_waveform[0][i][2];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* auto-restart in running mode */
|
|
if (m_thread == NULL && m_running)
|
|
Start();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
unsigned char buffer[100000];
|
|
|
|
int Osci::SaveWaveforms(MXML_WRITER *xml, int fd)
|
|
{
|
|
char str[80], name[80];
|
|
unsigned char *p;
|
|
unsigned short d;
|
|
float t;
|
|
int size;
|
|
static unsigned char *buffer;
|
|
static int buffer_size = 0;
|
|
|
|
if (xml == NULL && fd == 0)
|
|
return 0;
|
|
|
|
if (xml) {
|
|
mxml_start_element(xml, "Event");
|
|
sprintf(str, "%d", m_evSerial);
|
|
mxml_write_element(xml, "Serial", str);
|
|
sprintf(str, "%4d/%02d/%02d %02d:%02d:%02d.%03d", m_evTimestamp.Year, m_evTimestamp.Month,
|
|
m_evTimestamp.Day, m_evTimestamp.Hour, m_evTimestamp.Minute, m_evTimestamp.Second,
|
|
m_evTimestamp.Milliseconds);
|
|
mxml_write_element(xml, "Time", str);
|
|
mxml_write_element(xml, "HUnit", "ns");
|
|
mxml_write_element(xml, "VUnit", "mV");
|
|
|
|
for (int b=0 ; b<m_nBoards ; b++) {
|
|
sprintf(str, "Board_%d", m_drs->GetBoard(b)->GetBoardSerialNumber());
|
|
mxml_start_element(xml, str);
|
|
sprintf(str, "%d", m_triggerCell[b]);
|
|
mxml_write_element(xml, "Trigger_Cell", str);
|
|
for (int i=0 ; i<4 ; i++) {
|
|
if (m_chnOn[b][i]) {
|
|
sprintf(str, "%u", m_drs->GetBoard(b)->GetScaler(i));
|
|
sprintf(name, "Scaler%d", i);
|
|
mxml_write_element(xml, name, str);
|
|
sprintf(str, "CHN%d", i+1);
|
|
mxml_start_element(xml, str);
|
|
strcpy(str, "\n");
|
|
for (int j=0 ; j<m_waveDepth ; j++) {
|
|
sprintf(str, "%1.3f,%1.1f", m_time[b][i][j], m_waveform[b][i][j]);
|
|
mxml_write_element(xml, "Data", str);
|
|
}
|
|
mxml_end_element(xml); // CHNx
|
|
}
|
|
}
|
|
mxml_end_element(xml); //Board
|
|
}
|
|
|
|
mxml_end_element(xml); // Event
|
|
}
|
|
|
|
if (fd) {
|
|
if (buffer_size == 0) {
|
|
buffer_size = 8; // file header + time header
|
|
buffer_size += m_nBoards * (4 + 4*(4+m_waveDepth*4)); // bin widths
|
|
buffer_size += 24 + m_nBoards * (8 + 4*(8+m_waveDepth*2));
|
|
buffer = (unsigned char *)malloc(buffer_size);
|
|
}
|
|
|
|
p = buffer;
|
|
|
|
if (m_evSerial == 1) {
|
|
memcpy(p, "DRS2", 4); // File identifier and version
|
|
p += 4;
|
|
|
|
// time calibration header
|
|
memcpy(p, "TIME", 4);
|
|
p += 4;
|
|
|
|
for (int b=0 ; b<m_nBoards ; b++) {
|
|
// store board serial number
|
|
sprintf((char *)p, "B#");
|
|
p += 2;
|
|
*(unsigned short *)p = m_drs->GetBoard(b)->GetBoardSerialNumber();
|
|
p += sizeof(unsigned short);
|
|
|
|
for (int i=0 ; i<4 ; i++) {
|
|
if (m_chnOn[b][i]) {
|
|
sprintf((char *)p, "C%03d", i+1);
|
|
p += 4;
|
|
float tcal[2048];
|
|
m_drs->GetBoard(b)->GetTimeCalibration(0, i*2, 0, tcal, 0);
|
|
for (int j=0 ; j<m_waveDepth ; j++) {
|
|
// save binary time as 32-bit float value
|
|
if (m_waveDepth == 2048) {
|
|
t = (tcal[j % 1024]+tcal[(j+1) % 1024])/2;
|
|
j++;
|
|
} else
|
|
t = tcal[j];
|
|
*(float *)p = t;
|
|
p += sizeof(float);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
memcpy(p, "EHDR", 4);
|
|
p += 4;
|
|
*(int *)p = m_evSerial;
|
|
p += sizeof(int);
|
|
*(unsigned short *)p = m_evTimestamp.Year;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = m_evTimestamp.Month;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = m_evTimestamp.Day;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = m_evTimestamp.Hour;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = m_evTimestamp.Minute;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = m_evTimestamp.Second;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = m_evTimestamp.Milliseconds;
|
|
p += sizeof(unsigned short);
|
|
*(unsigned short *)p = (unsigned short)(m_inputRange * 1000); // range
|
|
p += sizeof(unsigned short);
|
|
|
|
for (int b=0 ; b<m_nBoards ; b++) {
|
|
|
|
// store board serial number
|
|
sprintf((char *)p, "B#");
|
|
p += 2;
|
|
*(unsigned short *)p = m_drs->GetBoard(b)->GetBoardSerialNumber();
|
|
p += sizeof(unsigned short);
|
|
|
|
// store trigger cell
|
|
sprintf((char *)p, "T#");
|
|
p += 2;
|
|
*(unsigned short *)p = m_triggerCell[b];
|
|
p += sizeof(unsigned short);
|
|
|
|
for (int i=0 ; i<4 ; i++) {
|
|
if (m_chnOn[b][i]) {
|
|
sprintf((char *)p, "C%03d", i+1);
|
|
p += 4;
|
|
|
|
unsigned int s = m_drs->GetBoard(b)->GetScaler(i);
|
|
memcpy(p, &s, sizeof(int));
|
|
p += sizeof(int);
|
|
|
|
for (int j=0 ; j<m_waveDepth ; j++) {
|
|
// save binary date as 16-bit value:
|
|
// 0 = -0.5V, 65535 = +0.5V for range 0
|
|
// 0 = -0.05V, 65535 = +0.95V for range 0.45
|
|
if (m_waveDepth == 2048) {
|
|
// in cascaded mode, save 1024 values as averages of the 2048 values
|
|
d = (unsigned short)(((m_waveform[b][i][j]+m_waveform[b][i][j+1])/2000.0 - m_inputRange + 0.5) * 65535);
|
|
*(unsigned short *)p = d;
|
|
p += sizeof(unsigned short);
|
|
j++;
|
|
} else {
|
|
d = (unsigned short)((m_waveform[b][i][j]/1000.0 - m_inputRange + 0.5) * 65535);
|
|
*(unsigned short *)p = d;
|
|
p += sizeof(unsigned short);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
size = p-buffer;
|
|
assert(size <= buffer_size);
|
|
int n = write(fd, buffer, size);
|
|
if (n != size)
|
|
return -1;
|
|
}
|
|
|
|
m_evSerial++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetSamplingSpeed(double freq)
|
|
{
|
|
if (m_drs->GetNumberOfBoards() == 0) {
|
|
m_samplingSpeed = freq;
|
|
return;
|
|
}
|
|
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++) {
|
|
DRSBoard *b = m_drs->GetBoard(i);
|
|
|
|
b->SetFrequency(freq, true);
|
|
m_samplingSpeed = b->GetNominalFrequency();
|
|
wxMilliSleep(10);
|
|
|
|
if (b->GetDRSType() == 4 && !b->IsPLLLocked()) {
|
|
wxString str;
|
|
|
|
#ifdef HAVE_VME
|
|
if (b->GetTransport() == 1)
|
|
str.Printf(wxT("PLLs did not lock on VME board slot %2d %s, serial #%d"),
|
|
(b->GetSlotNumber() >> 1)+2, ((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower",
|
|
b->GetBoardSerialNumber());
|
|
else
|
|
#endif
|
|
str.Printf(wxT("PLLs did not lock on USB board #%d, serial #%d"),
|
|
b->GetSlotNumber(), b->GetBoardSerialNumber());
|
|
|
|
wxMessageBox(str, wxT("DRS Oscilloscope Error"), wxOK | wxICON_STOP, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double Osci::GetSamplingSpeed()
|
|
{
|
|
if (m_drs->GetNumberOfBoards() > 0) {
|
|
DRSBoard *b = m_drs->GetBoard(m_board);
|
|
return b->GetNominalFrequency();
|
|
}
|
|
return m_samplingSpeed;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double Osci::GetTrueSamplingSpeed()
|
|
{
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
return m_drs->GetBoard(m_board)->GetTrueFrequency();
|
|
return m_samplingSpeed;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double Osci::GetMaxSamplingSpeed()
|
|
{
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
if (m_drs->GetBoard(i)->GetDRSType() == 2)
|
|
return 4;
|
|
return 5;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double Osci::GetMinSamplingSpeed()
|
|
{
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
if (m_drs->GetBoard(i)->GetDRSType() == 4) {
|
|
if (m_drs->GetBoard(i)->GetBoardSerialNumber() == 2146 ||
|
|
m_drs->GetBoard(i)->GetBoardSerialNumber() == 2205 ||
|
|
m_drs->GetBoard(i)->GetBoardSerialNumber() == 2208)
|
|
return 0.5; // special modified boards for RFBeta & Slow Muons
|
|
return 0.7;
|
|
}
|
|
return 0.5;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
int Osci::GetWaveformDepth(int channel)
|
|
{
|
|
if (channel == 4 && m_clkOn && m_waveDepth > kNumberOfBins)
|
|
return m_waveDepth - kNumberOfBins; // clock channel has only 1024 bins
|
|
|
|
return m_waveDepth;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
float *Osci::GetTime(int b, int channel)
|
|
{
|
|
if (m_drs->GetNumberOfBoards() > 0) {
|
|
if (m_drs->GetBoard(m_board)->GetBoardType() < 9) {
|
|
if (channel == 3 && m_clkOn)
|
|
return (float *)m_timeClk[b];
|
|
}
|
|
}
|
|
|
|
return (float *)m_time[b][channel];
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool Osci::IsTCalibrated(void)
|
|
{
|
|
return m_drs->GetBoard(m_board)->IsTimingCalibrationValid();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool Osci::IsVCalibrated(void)
|
|
{
|
|
return m_drs->GetBoard(m_board)->IsVoltageCalibrationValid();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool Osci::GetTimeCalibration(int chip, int channel, int mode, float *time, bool force)
|
|
{
|
|
if (!force && !IsTCalibrated())
|
|
return false;
|
|
|
|
m_drs->GetBoard(m_board)->GetTimeCalibration(chip, channel, mode, time, force);
|
|
return true;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetTriggerLevel(double level)
|
|
{
|
|
m_trgLevel[0] = m_trgLevel[1] = m_trgLevel[2] = m_trgLevel[3] = level;
|
|
|
|
// only change trigger of current board
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
m_drs->GetBoard(m_board)->SetTriggerLevel(level);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetTriggerPolarity(bool negative)
|
|
{
|
|
m_trgNegative[m_board] = negative;
|
|
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
m_drs->GetBoard(m_board)->SetTriggerPolarity(negative);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetIndividualTriggerLevel(int channel, double level)
|
|
{
|
|
m_trgLevel[channel] = level;
|
|
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
m_drs->GetBoard(m_board)->SetIndividualTriggerLevel(channel, level);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetTriggerDelay(int delay)
|
|
{
|
|
m_trgDelay = delay;
|
|
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
m_drs->GetBoard(m_board)->SetTriggerDelayPercent(delay);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
int Osci::GetTriggerDelay()
|
|
{
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
return m_drs->GetBoard(m_board)->GetTriggerDelay();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double Osci::GetTriggerDelayNs()
|
|
{
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
return m_drs->GetBoard(m_board)->GetTriggerDelayNs();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetTriggerConfig(int tc)
|
|
{
|
|
if (m_drs->GetBoard(m_board)->GetBoardType() == 8 || m_drs->GetBoard(m_board)->GetBoardType() == 9) {
|
|
m_drs->GetBoard(m_board)->EnableTrigger(1, 0); // enable trigger
|
|
m_drs->GetBoard(m_board)->SetTriggerConfig(tc);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetChnOn(int board, int chn, bool flag)
|
|
{
|
|
m_chnOn[board][chn] = flag;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetClkOn(bool flag)
|
|
{
|
|
m_clkOn = flag;
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++) {
|
|
m_drs->GetBoard(i)->EnableTcal(flag ? 1 : 0, 0);
|
|
if (m_drs->GetBoard(i)->GetBoardType() == 5 || m_drs->GetBoard(i)->GetBoardType() == 7 ||
|
|
m_drs->GetBoard(i)->GetBoardType() == 8 || m_drs->GetBoard(i)->GetBoardType() == 9)
|
|
m_drs->GetBoard(i)->SelectClockSource(0); // select sync. clock
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetRefclk(int board, bool flag)
|
|
{
|
|
m_refClk[board] = flag;
|
|
// only change clock of current board and not all boards to allow daisy-chaining
|
|
if (m_drs->GetNumberOfBoards()) {
|
|
if (m_drs->GetBoard(board)->GetBoardType() == 6 ||
|
|
m_drs->GetBoard(board)->GetBoardType() == 8 ||
|
|
m_drs->GetBoard(board)->GetBoardType() == 9)
|
|
m_drs->GetBoard(board)->SetRefclk(flag);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetCalibVoltage(bool flag, double voltage)
|
|
{
|
|
m_calibOn = flag;
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
m_drs->GetBoard(i)->EnableAcal(flag, voltage);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::SetInputRange(double center)
|
|
{
|
|
m_inputRange = center;
|
|
for (int i=0 ; i< m_drs->GetNumberOfBoards() ; i++)
|
|
m_drs->GetBoard(i)->SetInputRange(center);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double Osci::GetCalibratedInputRange()
|
|
{
|
|
return m_drs->GetBoard(m_board)->GetCalibratedInputRange();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
unsigned int Osci::GetScaler(int channel)
|
|
{
|
|
if (m_drs->GetNumberOfBoards() > 0)
|
|
return m_drs->GetBoard(m_board)->GetScaler(channel);
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void Osci::CorrectTriggerPoint(double t)
|
|
{
|
|
int i, n, min_i, trgChn;
|
|
double min_dt, dt, t0, t1, trigPoint[2*kNumberOfBins];
|
|
float *pt;
|
|
|
|
/*---- shift first channel according to trigger point ----*/
|
|
|
|
for (i=trgChn=0 ; i<5 ; i++)
|
|
if (m_trgConfig[0] & (1<<i)) {
|
|
trgChn = i;
|
|
break;
|
|
}
|
|
|
|
if (trgChn == 3 && m_clkOn)
|
|
pt = m_timeClk[0];
|
|
else
|
|
pt = m_time[0][trgChn];
|
|
|
|
if (trgChn < 4) {
|
|
// search and store all points
|
|
for (i = n = 0 ; i<m_waveDepth-1 ; i++) {
|
|
if (m_trgNegative[m_board]) {
|
|
if (m_waveform[0][trgChn][i] >= m_trgLevel[trgChn]*1000 &&
|
|
m_waveform[0][trgChn][i+1] < m_trgLevel[trgChn]*1000) {
|
|
|
|
dt = pt[i+1] - pt[i];
|
|
dt = dt * 1 / (1 + (m_trgLevel[trgChn]*1000-m_waveform[0][trgChn][i+1])/(m_waveform[0][trgChn][i]-m_trgLevel[trgChn]*1000));
|
|
trigPoint[n++] = pt[i] + dt;
|
|
}
|
|
} else {
|
|
if (m_waveform[0][trgChn][i] <= m_trgLevel[trgChn]*1000 &&
|
|
m_waveform[0][trgChn][i+1] > m_trgLevel[trgChn]*1000) {
|
|
|
|
dt = pt[i+1] - pt[i];
|
|
dt = dt * 1 / (1 + (m_waveform[0][trgChn][i+1]-m_trgLevel[trgChn]*1000)/(m_trgLevel[trgChn]*1000-m_waveform[0][trgChn][i]));
|
|
trigPoint[n++] = pt[i] + dt;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (n > 2) {
|
|
/* search trigger point closest to trigger in case of many trigger points (like a sine wave) */
|
|
min_dt = 1e6;
|
|
min_i = -1;
|
|
for (i=0 ; i<n ; i++) {
|
|
if (fabs(trigPoint[i] - t) < min_dt) {
|
|
min_dt = fabs(trigPoint[i] - t);
|
|
min_i = i;
|
|
}
|
|
}
|
|
} else {
|
|
/* choose first trigger point, to avoid jumping of the trigger position after correction */
|
|
min_i = 0;
|
|
}
|
|
|
|
/* correct times to shift waveform to trigger point */
|
|
if (n > 0) {
|
|
dt = trigPoint[min_i] - t;
|
|
|
|
for (int b=0 ; b<m_nBoards ; b++) {
|
|
for (int w=0 ; w<4 ; w++)
|
|
for (i=0 ; i<m_waveDepth ; i++)
|
|
m_time[b][w][i] -= dt;
|
|
for (i=0 ; i<kNumberOfBins ; i++)
|
|
m_timeClk[b][i] -= dt;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---- shift other channels according to cell #0 in multi-board mode ----*/
|
|
|
|
t0 = m_time[0][0][(1024-m_triggerCell[0]) % 1024];
|
|
|
|
for (int b=1 ; b<m_nBoards ; b++) {
|
|
if (!m_refClk[b])
|
|
continue; // skip boards if no external refclk
|
|
|
|
t1 = m_time[b][0][(1024-m_triggerCell[b]) % 1024];
|
|
dt = t1 - t0;
|
|
if (dt < 0)
|
|
dt += 1024/m_drs->GetBoard(0)->GetTrueFrequency();
|
|
|
|
for (int w=0 ; w<4 ; w++)
|
|
for (i=0 ; i<m_waveDepth ; i++)
|
|
m_time[b][w][i] -= dt;
|
|
for (i=0 ; i<kNumberOfBins ; i++)
|
|
m_timeClk[b][i] -= dt;
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
int spos[1024];
|
|
|
|
void Osci::RemoveSpikes(int b, bool cascading)
|
|
{
|
|
int i, j, k, l, c, ofs, nChn;
|
|
double x, y;
|
|
int sp[8][10];
|
|
int rsp[10], rot_sp[10];
|
|
int n_sp[8], n_rsp;
|
|
float wf[8][2048];
|
|
int nNeighbor, nSymmetric;
|
|
|
|
nChn = cascading ? 8 : 4;
|
|
|
|
/* rotate waveform back relative to cell #0 */
|
|
if (cascading) {
|
|
if (m_rotated) {
|
|
for (i=0 ; i<nChn ; i++)
|
|
for (j=0 ; j<1024 ; j++)
|
|
wf[i][(j+m_triggerCell[b]) % 1024] = m_waveform[b][i/2][(i%2)*1024+j];
|
|
} else {
|
|
for (i=0 ; i<nChn ; i++)
|
|
for (j=0 ; j<1024 ; j++)
|
|
wf[i][j] = m_waveform[b][i/2][(i%2)*1024+j];
|
|
}
|
|
} else {
|
|
if (m_rotated) {
|
|
for (i=0 ; i<nChn ; i++)
|
|
for (j=0 ; j<1024 ; j++)
|
|
wf[i][(j+m_triggerCell[b]) % 1024] = m_waveform[b][i][j];
|
|
} else {
|
|
for (i=0 ; i<nChn ; i++)
|
|
for (j=0 ; j<1024 ; j++)
|
|
wf[i][j] = m_waveform[b][i][j];
|
|
}
|
|
}
|
|
|
|
|
|
memset(sp, 0, sizeof(sp));
|
|
memset(n_sp, 0, sizeof(n_sp));
|
|
memset(rsp, 0, sizeof(rsp));
|
|
n_rsp = 0;
|
|
|
|
/* find spikes with special high-pass filter */
|
|
for (j=0 ; j<1024 ; j++) {
|
|
for (i=0 ; i<nChn ; i++) {
|
|
if (-wf[i][j]+wf[i][(j+1) % 1024]+wf[i][(j+2) % 1024]-wf[i][(j+3) % 1024] > 20) {
|
|
if (n_sp[i] < 10) // record maximum of 10 spikes
|
|
sp[i][n_sp[i]++] = j;
|
|
else
|
|
return; // too many spikes -> something wrong
|
|
spos[j]++;
|
|
}
|
|
if (-wf[i][j]+wf[i][(j+1) % 1024]+wf[i][(j+2) % 1024]-wf[i][(j+3) % 1024] < -20) {
|
|
if (n_sp[i] < 10) // record maximum of 10 spikes
|
|
sp[i][n_sp[i]++] = j;
|
|
else
|
|
return; // too many spikes -> something wrong
|
|
spos[j]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* find spikes at cell #0 and #1023 */
|
|
for (i=0 ; i<nChn ; i++) {
|
|
if (wf[i][0]+wf[i][1]-2*wf[i][2] > 20) {
|
|
if (n_sp[i] < 10)
|
|
sp[i][n_sp[i]++] = 0;
|
|
}
|
|
if (-2*wf[i][1021]+wf[i][1022]+wf[i][1023] > 20) {
|
|
if (n_sp[i] < 10)
|
|
sp[i][n_sp[i]++] = 1020;
|
|
}
|
|
}
|
|
|
|
/* go through all spikes and look for symmetric spikes and neighbors */
|
|
for (i=0 ; i<nChn ; i++) {
|
|
for (j=0 ; j<n_sp[i] ; j++) {
|
|
/* check if this spike has a symmetric partner in any channel */
|
|
for (k=nSymmetric=0 ; k<nChn ; k++) {
|
|
for (l=0 ; l<n_sp[k] ; l++)
|
|
if (sp[i][j] == (1020-sp[k][l]+1024) % 1024) {
|
|
nSymmetric++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* check if this spike has same spike in any other channels */
|
|
for (k=nNeighbor=0 ; k<nChn ; k++)
|
|
if (i != k) {
|
|
for (l=0 ; l<n_sp[k] ; l++)
|
|
if (sp[i][j] == sp[k][l]) {
|
|
nNeighbor++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nSymmetric + nNeighbor >= 2) {
|
|
/* if at least two matching spikes, treat this as a real spike */
|
|
for (k=0 ; k<n_rsp ; k++)
|
|
if (rsp[k] == sp[i][j])
|
|
break;
|
|
if (n_rsp < 10 && k == n_rsp)
|
|
rsp[n_rsp++] = sp[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* rotate spikes according to trigger cell */
|
|
if (m_rotated) {
|
|
for (i=0 ; i<n_rsp ; i++)
|
|
rot_sp[i] = (rsp[i] - m_triggerCell[b] + 1024) % 1024;
|
|
} else {
|
|
for (i=0 ; i<n_rsp ; i++)
|
|
rot_sp[i] = rsp[i];
|
|
}
|
|
|
|
/* recognize spikes if at least one channel has it */
|
|
for (k=0 ; k<n_rsp ; k++) {
|
|
for (i=0 ; i<nChn ; i++) {
|
|
|
|
if (cascading) {
|
|
c = i/2;
|
|
ofs = (i%2)*1024;
|
|
} else {
|
|
c = i;
|
|
ofs = 0;
|
|
}
|
|
if (k < n_rsp-1 && rsp[k] == 0 && rsp[k+1] == 1020) {
|
|
/* remove double spike */
|
|
j = rot_sp[k] > rot_sp[k+1] ? rot_sp[k+1] : rot_sp[k];
|
|
x = m_waveform[b][c][ofs+(j+1) % 1024];
|
|
y = m_waveform[b][c][ofs+(j+6) % 1024];
|
|
if (fabs(x-y) < 15) {
|
|
m_waveform[b][c][ofs+(j+2) % 1024] = x + 1*(y-x)/5;
|
|
m_waveform[b][c][ofs+(j+3) % 1024] = x + 2*(y-x)/5;
|
|
m_waveform[b][c][ofs+(j+4) % 1024] = x + 3*(y-x)/5;
|
|
m_waveform[b][c][ofs+(j+5) % 1024] = x + 4*(y-x)/5;
|
|
} else {
|
|
m_waveform[b][c][ofs+(j+2) % 1024] -= 14.8f;
|
|
m_waveform[b][c][ofs+(j+3) % 1024] -= 14.8f;
|
|
m_waveform[b][c][ofs+(j+4) % 1024] -= 14.8f;
|
|
m_waveform[b][c][ofs+(j+5) % 1024] -= 14.8f;
|
|
}
|
|
} else {
|
|
/* remove single spike */
|
|
x = m_waveform[b][c][ofs+rot_sp[k]];
|
|
y = m_waveform[b][c][ofs+(rot_sp[k]+3) % 1024];
|
|
|
|
if (fabs(x-y) < 15) {
|
|
m_waveform[b][c][ofs+(rot_sp[k]+1) % 1024] = x + 1*(y-x)/3;
|
|
m_waveform[b][c][ofs+(rot_sp[k]+2) % 1024] = x + 2*(y-x)/3;
|
|
} else {
|
|
m_waveform[b][c][ofs+(rot_sp[k]+1) % 1024] -= 14.8f;
|
|
m_waveform[b][c][ofs+(rot_sp[k]+2) % 1024] -= 14.8f;
|
|
}
|
|
}
|
|
}
|
|
if (k < n_rsp-1 && rsp[k] == 0 && rsp[k+1] == 1020)
|
|
k++; // skip second half of double spike
|
|
}
|
|
|
|
/* uncomment to show unfixed spikes
|
|
m_skipDisplay = true;
|
|
for (i=0 ; i<1024 ; i++)
|
|
for (j=0 ; j<nChn ; j++) {
|
|
if (m_waveform[j][i] > 10 || m_waveform[j][i] < -10) {
|
|
m_skipDisplay = false;
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|