/* * 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 #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 ; bStopThread(); 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 ; iGetDRS()->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 ; iGetBoard(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 ; iGetBoard(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 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 ; jGetChannelCascading() == 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 ; iGetBoard(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 ; bGetBoard(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 ; jGetBoard(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 ; jGetBoard(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 ; jGetNumberOfBoards() == 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<= 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 0) { dt = trigPoint[min_i] - t; for (int b=0 ; bGetBoard(0)->GetTrueFrequency(); for (int w=0 ; w<4 ; w++) for (i=0 ; i 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 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= 2) { /* if at least two matching spikes, treat this as a real spike */ for (k=0 ; 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 10 || m_waveform[j][i] < -10) { m_skipDisplay = false; break; } } */ } /*------------------------------------------------------------------*/