1766 lines
50 KiB
C++
1766 lines
50 KiB
C++
/*
|
|
* Osci.cpp
|
|
* DRS oscilloscope main class
|
|
* $Id: DOFrame.cpp 22327 2016-10-11 13:18:26Z ritt $
|
|
*/
|
|
|
|
#define MULTI_THREAD_READOUT
|
|
|
|
#include "DRSOscInc.h"
|
|
#include "strlcpy.h"
|
|
|
|
#include "pos.xpm"
|
|
#include "neg.xpm"
|
|
|
|
#ifndef O_TEXT
|
|
#define O_TEXT 0
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
char svn_revision[] = "$Id: DOFrame.cpp 22327 2016-10-11 13:18:26Z ritt $";
|
|
|
|
char drsosc_version[] = "5.0.6";
|
|
|
|
// critical section between main and event processing thread
|
|
wxCriticalSection *g_epcs;
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
class MyPrintout: public wxPrintout
|
|
{
|
|
public:
|
|
MyPrintout(DOScreen *screen, const wxChar *title):wxPrintout(title) { m_screen = screen; }
|
|
bool OnPrintPage(int page);
|
|
private:
|
|
DOScreen *m_screen;
|
|
};
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
BEGIN_EVENT_TABLE(DOFrame, wxFrame)
|
|
EVT_TIMER (wxID_ANY, DOFrame::OnTimer )
|
|
EVT_MENU (wxID_EXIT, DOFrame::OnExit )
|
|
END_EVENT_TABLE()
|
|
|
|
DOFrame::DOFrame( wxWindow* parent )
|
|
:
|
|
DOFrame_fb( parent )
|
|
{
|
|
// colors for four channels
|
|
m_color[0] = wxColor(255, 255, 0); // yellow
|
|
m_color[1] = wxColor(170, 170, 255); // light blue
|
|
m_color[2] = wxColor(255, 150, 150); // light red
|
|
m_color[3] = wxColor(150, 255, 150); // light green
|
|
m_color[4] = wxColor(170, 170, 170); // grey for ext trigger
|
|
m_color[5] = wxColor(170, 170, 170); // grey for combinatorial trigger
|
|
|
|
// colors for printing
|
|
m_pcolor[0] = wxColor(128, 128, 0); // dark yellow
|
|
m_pcolor[1] = wxColor( 0, 0, 255); // blue
|
|
m_pcolor[2] = wxColor(255, 0, 0); // red
|
|
m_pcolor[3] = wxColor( 0, 255, 0); // green
|
|
m_pcolor[4] = wxColor(128, 128, 128); // grey for ext trigger
|
|
m_pcolor[5] = wxColor(128, 128, 128); // grey for combinatorial trigger
|
|
|
|
// initialize variables
|
|
m_acqPerSecond = 0;
|
|
m_lastTriggerUpdate = time(NULL);
|
|
m_reqSamplingSpeed = 1;
|
|
m_WFFile = NULL;
|
|
m_WFfd = 0;
|
|
m_nSaved = 0;
|
|
m_actCursor = 0;
|
|
m_cursorA = m_cursorB = false;
|
|
m_snap = false;
|
|
m_hideControls = false;
|
|
m_stat = true;
|
|
m_hist = false;
|
|
m_indicator = true;
|
|
m_first = true;
|
|
m_freqLocked = false;
|
|
m_nStat = 1000;
|
|
m_progress = 0;
|
|
m_oldIdle = false;
|
|
|
|
m_configDialog = NULL;
|
|
m_measureDialog = NULL;
|
|
m_triggerDialog = NULL;
|
|
m_displayDialog = NULL;
|
|
m_epthread = NULL;
|
|
g_epcs = NULL;
|
|
|
|
// initialize source
|
|
m_board = 0;
|
|
m_firstChannel = 0;
|
|
m_chnSection = 0;
|
|
m_multiBoard = false;
|
|
m_splitMode = false;
|
|
m_transpTrigger = false;
|
|
|
|
// initialize settings
|
|
m_trgCorr = true;
|
|
|
|
for (int b=0 ; b<MAX_N_BOARDS ; b++) {
|
|
m_refClk[b] = false; // internal Refclk
|
|
m_HScale[b] = 4; // 20 ns / div.
|
|
m_HOffset[b] = 0;
|
|
|
|
m_trgMode[b] = TM_AUTO;
|
|
m_trgConfig[b] = (1<<0); // CH1
|
|
m_trgLevel[b][0] = m_trgLevel[b][1] = m_trgLevel[b][2] = m_trgLevel[b][3] = 0.25;
|
|
m_trgDelay[b] = 0;
|
|
m_trgDelayNs[b] = 0;
|
|
m_trgNegative[b] = false;
|
|
m_trgConfig[b] = 0;
|
|
m_trgConfigEnabled[b] = true;
|
|
|
|
for (int i=0 ; i<4 ; i++) {
|
|
m_chnOn[b][i] = false;
|
|
m_chnOffset[b][i] = 0;
|
|
m_chnScale[b][i] = 6; // 100 mV / div
|
|
}
|
|
|
|
m_chnOn[b][0] = true;
|
|
m_range[b] = 0;
|
|
}
|
|
|
|
m_clkOn = false;
|
|
m_spikeRemoval = true;
|
|
m_displayScalers = false;
|
|
|
|
// overwrite settings from configuration file
|
|
LoadConfig(m_xmlError, sizeof(m_xmlError));
|
|
|
|
// create Osci object
|
|
#ifdef MULTI_THREAD_READOUT
|
|
m_osci = new Osci(m_reqSamplingSpeed, true);
|
|
#else
|
|
m_osci = new Osci(m_reqSamplingSpeed, false);
|
|
#endif
|
|
|
|
// update sampling speed from calibration of first board if not in configuration
|
|
if (m_reqSamplingSpeed == 0)
|
|
m_reqSamplingSpeed = ((int)(m_osci->GetTrueSamplingSpeed()*100+0.5))/100.0;
|
|
else
|
|
m_osci->SetSamplingSpeed(m_reqSamplingSpeed);
|
|
|
|
// turn off multi board mode if only one board present
|
|
if (m_osci->GetNumberOfBoards() < 2) {
|
|
m_multiBoard = false;
|
|
m_splitMode = false;
|
|
}
|
|
|
|
// turn off transparent mode for boards with old firmware
|
|
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
if (m_osci->GetBoard(i)->GetFirmwareVersion() < 21699)
|
|
m_trgConfig[i] &= ~(1<<15);
|
|
}
|
|
|
|
// set section (needed before ConfigDialog) to display 2048-bin mode
|
|
if (m_osci->GetNumberOfBoards() > 0 && m_osci->GetBoard(0)->Is2048ModeCapable())
|
|
m_chnSection = 2;
|
|
else
|
|
m_chnSection = 0;
|
|
m_osci->SelectChannel(m_firstChannel, m_chnSection);
|
|
|
|
// create Measurement objects
|
|
for (int i=0 ; i<Measurement::N_MEASUREMENTS ; i++)
|
|
for (int chn=0 ; chn<4 ; chn++) {
|
|
m_measurement[i][chn] = new Measurement(this, i);
|
|
m_measFlag[i][chn] = false;
|
|
}
|
|
|
|
// create screen object
|
|
m_screen = new DOScreen(m_pnScreen, m_osci, this);
|
|
wxBoxSizer *vbox1 = new wxBoxSizer(wxVERTICAL);
|
|
vbox1->Add(m_screen, 1, wxEXPAND);
|
|
m_pnScreen->SetSizer(vbox1);
|
|
|
|
#ifdef _MSC_VER
|
|
/* adjust font size under Windows */
|
|
m_stScale1->SetFont(wxFont(8, wxFONTFAMILY_DEFAULT,
|
|
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
|
m_stScale2->SetFont(wxFont(8, wxFONTFAMILY_DEFAULT,
|
|
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
|
m_stScale3->SetFont(wxFont(8, wxFONTFAMILY_DEFAULT,
|
|
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
|
m_stScale4->SetFont(wxFont(8, wxFONTFAMILY_DEFAULT,
|
|
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
|
#endif
|
|
|
|
// create timer
|
|
m_timer = new wxTimer(this);
|
|
|
|
// create modeless dialog boxes
|
|
m_configDialog = new ConfigDialog(this);
|
|
m_measureDialog = new MeasureDialog(this);
|
|
m_triggerDialog = new TriggerDialog(this);
|
|
m_displayDialog = new DisplayDialog(this);
|
|
|
|
// set position of dialog boxes conveniently
|
|
int w, h, cw, ch, mw, mh, dw, dh, x, y;
|
|
wxDisplaySize(&dw, &dh);
|
|
m_configDialog->GetSize(&cw, &ch);
|
|
m_measureDialog->GetSize(&mw, &mh);
|
|
this->GetSize(&w, &h);
|
|
this->GetPosition(&x, &y);
|
|
|
|
x = x + w + 1;
|
|
if (x + cw > dw)
|
|
x = dw - cw - 1;
|
|
m_configDialog->Move(x, y);
|
|
|
|
x = x + cw + 1;
|
|
if (x + mw > dw)
|
|
x = dw - mw - 1;
|
|
m_measureDialog->Move(x, y);
|
|
|
|
// initialize status bar
|
|
CreateStatusBar();
|
|
UpdateStatusBar();
|
|
|
|
// start event processing thread
|
|
#ifdef MULTI_THREAD_READOUT
|
|
g_epcs = new wxCriticalSection();
|
|
m_epthread = new EPThread(this);
|
|
#endif
|
|
|
|
// Configure individual boards
|
|
|
|
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
m_board = i;
|
|
m_osci->SelectBoard(i);
|
|
|
|
int ofs = m_HOffset[i];
|
|
SetRefclk(m_board, m_refClk[i]); // update sampling speed according to Refclk
|
|
m_HOffset[i] = ofs;
|
|
|
|
m_osci->SetClkOn(m_clkOn);
|
|
m_osci->SetSpikeRemoval(m_spikeRemoval);
|
|
|
|
m_osci->SetTriggerDelay(m_trgDelay[i]);
|
|
m_trgDelayNs[i] = m_osci->GetTriggerDelayNs();
|
|
m_osci->SetInputRange(m_range[i]);
|
|
m_osci->SetTriggerMode(m_trgMode[i]);
|
|
m_osci->SetTriggerConfig(m_trgConfig[i]);
|
|
m_osci->SetTriggerLevel(m_trgLevel[0][i]);
|
|
m_osci->SetTriggerPolarity(m_trgNegative[i]);
|
|
m_osci->SetTriggerDelay(m_trgDelay[i]);
|
|
m_trgDelayNs[i] = m_osci->GetTriggerDelayNs();
|
|
for (int j=0 ; j<4 ; j++)
|
|
m_osci->SetChnOn(i, j, m_chnOn[i][j]);
|
|
}
|
|
|
|
// select first board
|
|
m_board = 0;
|
|
m_osci->SelectBoard(m_board);
|
|
|
|
// turn on multi board mode
|
|
if (m_multiBoard) {
|
|
m_osci->SetMultiBoard(true);
|
|
for (int i=1 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
SetTriggerConfig(i, (1<<4)); // select external trigger
|
|
SetTriggerPolarity(i, false); // positive trigger
|
|
}
|
|
m_osci->SelectBoard(m_board);
|
|
}
|
|
|
|
// set screen controls from values
|
|
UpdateControls();
|
|
|
|
// update screen settings from values
|
|
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
for (int j=0 ; j<4 ; j++) {
|
|
m_screen->SetChnOn(i, j, m_chnOn[i][j]);
|
|
m_screen->SetPos(i, j, m_chnOffset[i][j]/1000.0);
|
|
m_screen->SetScale(i, j, m_chnScale[i][j]);
|
|
}
|
|
m_screen->SetHScale(i, m_HScale[i]);
|
|
m_screen->SetScreenOffset(i, m_HOffset[i]);
|
|
}
|
|
m_screen->SetSplitMode(m_splitMode);
|
|
m_screen->SetDisplayScalers(m_displayScalers);
|
|
|
|
// Start acquisition
|
|
m_single = false;
|
|
m_running = true;
|
|
m_rearm = false;
|
|
m_osci->Enable(true);
|
|
m_osci->SetRunning(m_running);
|
|
m_timer->Start(100, true);
|
|
m_acquisitions = 0;
|
|
m_stopWatch.Start();
|
|
m_stopWatch1.Start();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
DOFrame::~DOFrame()
|
|
{
|
|
m_running = false;
|
|
if (m_timer->IsRunning())
|
|
m_timer->Stop();
|
|
delete m_timer;
|
|
|
|
SaveConfig();
|
|
|
|
if (m_epthread) {
|
|
m_osci->StopThread();
|
|
m_epthread->StopThread();
|
|
}
|
|
|
|
/* close file if open */
|
|
if (m_WFFile || m_WFfd)
|
|
CloseWFFile(false);
|
|
|
|
if (g_epcs)
|
|
delete g_epcs;
|
|
|
|
for (int i=0 ; i<Measurement::N_MEASUREMENTS ; i++)
|
|
for (int chn=0 ; chn<4 ; chn++)
|
|
delete m_measurement[i][chn];
|
|
|
|
delete m_osci;
|
|
delete m_screen;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::UpdateWaveforms()
|
|
{
|
|
if (m_epthread) {
|
|
int n = m_osci->IsMultiBoard() ? m_osci->GetNumberOfBoards() : 1;
|
|
|
|
g_epcs->Enter();
|
|
for (int i=0 ; i<n ; i++) {
|
|
for (int j=0 ; j<4 ; j++) {
|
|
memcpy(m_time[i][j], m_epthread->GetTime(i, j), m_osci->GetWaveformDepth(i)*sizeof(float));
|
|
memcpy(m_waveform[i][j], m_epthread->GetWaveform(i, j), m_osci->GetWaveformDepth(j)*sizeof(float));
|
|
}
|
|
}
|
|
g_epcs->Leave();
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::ClearWaveforms()
|
|
{
|
|
// used when switching between boards
|
|
if (m_epthread) {
|
|
if (!m_osci->IsMultiBoard())
|
|
m_epthread->ClearWaveforms();
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::UpdateControls()
|
|
{
|
|
if (m_osci->IsMultiBoard() && !m_transpTrigger && m_board > 0) {
|
|
m_slTrgLevel->Enable(false);
|
|
m_rbAuto->Enable(false);
|
|
m_rbNormal->Enable(false);
|
|
m_bpPolarity->Enable(false);
|
|
} else {
|
|
m_slTrgLevel->Enable(true);
|
|
m_rbAuto->Enable(true);
|
|
m_rbNormal->Enable(true);
|
|
m_bpPolarity->Enable(true);
|
|
m_btTrgCfg->Enable();
|
|
}
|
|
|
|
m_slTrgLevel->SetValue((int)(-m_trgLevel[m_board][0]*1000));
|
|
if (m_trgMode[m_board] == TM_AUTO)
|
|
m_rbAuto->SetValue(1);
|
|
else
|
|
m_rbNormal->SetValue(1);
|
|
if (m_trgNegative[m_board])
|
|
m_bpPolarity->SetBitmapLabel(wxBitmap(neg_xpm));
|
|
else
|
|
m_bpPolarity->SetBitmapLabel(wxBitmap(pos_xpm));
|
|
|
|
m_rbSource->Enable(5, false); // disable "X" button
|
|
m_rbSource->SetSelection(GetTriggerChannel(m_board));
|
|
m_slTrgDelay->SetValue(100-m_trgDelay[m_board]);
|
|
|
|
m_btCh1->SetValue(m_chnOn[m_board][0]);
|
|
m_btCh2->SetValue(m_chnOn[m_board][1]);
|
|
m_btCh3->SetValue(m_chnOn[m_board][2]);
|
|
m_btCh4->SetValue(m_chnOn[m_board][3]);
|
|
|
|
m_slPos1->SetValue(m_chnOffset[m_board][0]/2);
|
|
m_slPos2->SetValue(m_chnOffset[m_board][1]/2);
|
|
m_slPos3->SetValue(m_chnOffset[m_board][2]/2);
|
|
m_slPos4->SetValue(m_chnOffset[m_board][3]/2);
|
|
|
|
for (int i=0 ; i<4 ; i++) {
|
|
m_screen->SetChnOn(m_board, i, m_chnOn[m_board][i]);
|
|
m_osci->SetChnOn(m_board, i, m_chnOn[m_board][i]);
|
|
m_screen->SetPos(m_board, i, m_chnOffset[m_board][i]/1000.0);
|
|
m_screen->SetScale(m_board, i, m_chnScale[m_board][i]);
|
|
|
|
wxString wxst;
|
|
if (DOScreen::m_scaleTable[m_chnScale[m_board][i]] >= 1000)
|
|
wxst.Printf(wxT("%d V"), DOScreen::m_scaleTable[m_chnScale[m_board][i]]/1000);
|
|
else
|
|
wxst.Printf(wxT("%dmV"), DOScreen::m_scaleTable[m_chnScale[m_board][i]]);
|
|
|
|
if (i == 0) m_stScale1->SetLabel(wxst);
|
|
if (i == 1) m_stScale2->SetLabel(wxst);
|
|
if (i == 2) m_stScale3->SetLabel(wxst);
|
|
if (i == 3) m_stScale4->SetLabel(wxst);
|
|
}
|
|
|
|
// set initial horizontal scale and offset
|
|
m_screen->SetHScale(m_board, m_HScale[m_board]);
|
|
|
|
// calculate trigger position from screen offset
|
|
double trgFrac = (GetTrgPosition(m_board) - m_HOffset[m_board]) / m_screen->GetScreenSize(m_board);
|
|
RecalculateHOffset(trgFrac);
|
|
|
|
wxString wxstr;
|
|
if (DOScreen::m_hscaleTable[m_screen->GetHScale(m_board)] >= 1000) {
|
|
wxstr.Printf(wxT("%d us/div"), DOScreen::m_hscaleTable[m_HScale[m_board]]/1000);
|
|
} else {
|
|
wxstr.Printf(wxT("%d ns/div"), DOScreen::m_hscaleTable[m_HScale[m_board]]);
|
|
}
|
|
m_stHScale->SetLabel(wxstr);
|
|
|
|
// enable trigger config button for evaluation boards V4.0 & above
|
|
if (m_osci->GetNumberOfBoards() > 0) {
|
|
if (m_osci->GetCurrentBoard()->GetBoardType() < 8) {
|
|
EnableTriggerConfig(false);
|
|
} else {
|
|
if (m_osci->IsMultiBoard() && !m_transpTrigger && m_board > 0)
|
|
EnableTriggerConfig(false);
|
|
else
|
|
EnableTriggerConfig(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
float *DOFrame::GetTime(int b, int c)
|
|
{
|
|
if (m_epthread)
|
|
return m_time[b][c];
|
|
else
|
|
return m_osci->GetTime(b, c);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
float *DOFrame::GetWaveform(int b, int c)
|
|
{
|
|
if (m_epthread)
|
|
return m_waveform[b][c];
|
|
else
|
|
return m_osci->GetWaveform(b, c);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double DOFrame::GetActSamplingSpeed()
|
|
{
|
|
return m_osci->GetTrueSamplingSpeed();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::UpdateStatusBar()
|
|
{
|
|
if (m_osci->GetNumberOfBoards() == 0) {
|
|
SetStatusText(wxT("No DRS boards found!"));
|
|
} else {
|
|
DRSBoard *b = m_osci->GetCurrentBoard();
|
|
wxString wxstr;
|
|
|
|
#ifdef HAVE_VME
|
|
if (b->GetTransport() == 1)
|
|
wxstr.Printf(wxT("Connected to VME board slot %2d %s, serial #%d, firmware revision %d, T=%1.1lf C"),
|
|
(b->GetSlotNumber() >> 1)+2, ((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower",
|
|
b->GetBoardSerialNumber(), b->GetFirmwareVersion(), b->GetTemperature());
|
|
else
|
|
#endif
|
|
wxstr.Printf(wxT("Connected to USB board #%d, serial #%d, firmware revision %d, T=%1.1lf C"),
|
|
b->GetSlotNumber(), b->GetBoardSerialNumber(), b->GetFirmwareVersion(), b->GetTemperature());
|
|
|
|
SetStatusText(wxstr);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SaveConfig()
|
|
{
|
|
char str[256], name[256], filename[1024];
|
|
|
|
strcpy(filename, "drsosc.cfg");
|
|
|
|
#ifdef _MSC_VER
|
|
if (getenv("APPDATA")) {
|
|
strlcpy(filename, getenv("APPDATA"), sizeof(filename));
|
|
strlcat(filename, "\\DRSOsc", sizeof(filename));
|
|
mkdir(filename);
|
|
strlcat(filename, "\\drsosc.cfg", sizeof(filename));
|
|
} else
|
|
strcpy(filename, "drsosc.cfg");
|
|
#endif
|
|
|
|
#ifdef OS_DARWIN
|
|
strcpy(filename, "DRSOsc.app/drsosc.cfg");
|
|
#endif
|
|
|
|
MXML_WRITER *xml = mxml_open_file(filename);
|
|
if (xml == NULL) {
|
|
wxMessageBox(wxT("Error writing to configuration file"), wxT("DRSOsc"), wxOK | wxICON_ERROR);
|
|
return;
|
|
}
|
|
|
|
mxml_start_element(xml, "DRSOsc");
|
|
|
|
sprintf(str, "%d", (int)m_multiBoard);
|
|
mxml_write_element(xml, "MultiBoard", str);
|
|
|
|
sprintf(str, "%d", (int)m_splitMode);
|
|
mxml_write_element(xml, "SplitMode", str);
|
|
|
|
sprintf(str, "%d", (int)m_transpTrigger);
|
|
mxml_write_element(xml, "TranspTrig", str);
|
|
|
|
for (int b=0 ; b<m_osci->GetNumberOfBoards() ; b++) {
|
|
sprintf(str, "Board-%d", m_osci->GetBoard(b)->GetBoardSerialNumber());
|
|
mxml_start_element(xml, str);
|
|
|
|
sprintf(str, "%1.3lf", m_trgLevel[b][0]);
|
|
mxml_write_element(xml, "TrgLevel1", str);
|
|
sprintf(str, "%1.3lf", m_trgLevel[b][1]);
|
|
mxml_write_element(xml, "TrgLevel2", str);
|
|
sprintf(str, "%1.3lf", m_trgLevel[b][2]);
|
|
mxml_write_element(xml, "TrgLevel3", str);
|
|
sprintf(str, "%1.3lf", m_trgLevel[b][3]);
|
|
mxml_write_element(xml, "TrgLevel4", str);
|
|
sprintf(str, "%d", m_trgMode[b]);
|
|
mxml_write_element(xml, "TrgMode", str);
|
|
sprintf(str, "%d", m_trgNegative[b]);
|
|
mxml_write_element(xml, "TrgNegative", str);
|
|
sprintf(str, "%d", m_trgDelay[b]);
|
|
mxml_write_element(xml, "TrgDelay", str);
|
|
sprintf(str, "%d", m_trgConfig[b]);
|
|
mxml_write_element(xml, "TrgConfig", str);
|
|
|
|
sprintf(str, "%d", m_HScale[b]);
|
|
mxml_write_element(xml, "HScale", str);
|
|
sprintf(str, "%1.3lg", m_reqSamplingSpeed);
|
|
mxml_write_element(xml, "SamplingSpeed", str);
|
|
sprintf(str, "%d", m_freqLocked);
|
|
mxml_write_element(xml, "FreqLocked", str);
|
|
sprintf(str, "%d", m_HOffset[b]);
|
|
mxml_write_element(xml, "HOffset", str);
|
|
|
|
for (int i=0 ; i<4 ; i++) {
|
|
sprintf(name, "ChnOn%d", i);
|
|
sprintf(str, "%d", m_chnOn[b][i]);
|
|
mxml_write_element(xml, name, str);
|
|
sprintf(name, "ChnOffset%d", i);
|
|
sprintf(str, "%d", m_chnOffset[b][i]);
|
|
mxml_write_element(xml, name, str);
|
|
sprintf(name, "ChnScale%d", i);
|
|
sprintf(str, "%d", m_chnScale[b][i]);
|
|
mxml_write_element(xml, name, str);
|
|
}
|
|
|
|
sprintf(str, "%d", m_chnSection);
|
|
mxml_write_element(xml, "ChnSection", str);
|
|
|
|
sprintf(str, "%d", m_clkOn);
|
|
mxml_write_element(xml, "ClkOn", str);
|
|
|
|
sprintf(str, "%1.2lf", m_range[b]);
|
|
mxml_write_element(xml, "Range", str);
|
|
|
|
sprintf(str, "%d", m_spikeRemoval);
|
|
mxml_write_element(xml, "SpikeRemoval", str);
|
|
|
|
sprintf(str, "%d", (int)m_refClk[b]);
|
|
mxml_write_element(xml, "ExtRefclk", str);
|
|
|
|
sprintf(str, "%d", (int)m_displayScalers);
|
|
mxml_write_element(xml, "DisplayScalers", str);
|
|
|
|
mxml_end_element(xml);
|
|
}
|
|
|
|
mxml_end_element(xml);
|
|
mxml_close_file(xml);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::LoadConfig(char *error, int size)
|
|
{
|
|
int i, j, idx, fh;
|
|
char filename[1024];
|
|
|
|
strcpy(filename, "drsosc.cfg");
|
|
|
|
#ifdef _MSC_VER
|
|
if (getenv("APPDATA")) {
|
|
strlcpy(filename, getenv("APPDATA"), sizeof(filename));
|
|
strlcat(filename, "\\DRSOsc", sizeof(filename));
|
|
mkdir(filename);
|
|
strlcat(filename, "\\drsosc.cfg", sizeof(filename));
|
|
} else
|
|
strcpy(filename, "drsosc.cfg");
|
|
#endif
|
|
|
|
#ifdef OS_DARWIN
|
|
strcpy(filename, "DRSOsc.app/drsosc.cfg");
|
|
#endif
|
|
|
|
/* try to create configuration file to see if we have write access */
|
|
fh = open(filename, O_RDWR | O_CREAT | O_APPEND, 0644);
|
|
if (fh < 0) {
|
|
wxString str = wxT("Error creating configuration file ");
|
|
str += (const wxString &)filename;
|
|
wxMessageBox((const wxChar*)wxString::FromAscii((const char*)str), wxT("DRSOsc"), wxOK | wxICON_ERROR);
|
|
return;
|
|
}
|
|
close(fh);
|
|
|
|
PMXML_NODE root = mxml_parse_file(filename, error, size, NULL);
|
|
if (root == NULL) {
|
|
wxMessageBox(wxT("Error reading from configuration file"), wxT("DRSOsc"), wxOK | wxICON_ERROR);
|
|
return;
|
|
}
|
|
|
|
PMXML_NODE osc = mxml_find_node(root, "DRSOsc");
|
|
if (osc == NULL) {
|
|
mxml_free_tree(root);
|
|
return;
|
|
}
|
|
|
|
PMXML_NODE node = mxml_find_node(osc, "MultiBoard");
|
|
if (node) m_multiBoard = atoi(mxml_get_value(node)) > 0;
|
|
|
|
node = mxml_find_node(osc, "SplitMode");
|
|
if (node) m_splitMode = atoi(mxml_get_value(node)) > 0;
|
|
|
|
node = mxml_find_node(osc, "TranspTrig");
|
|
if (node) m_transpTrigger = atoi(mxml_get_value(node)) > 0;
|
|
|
|
for (i=idx=0 ; ; i++) {
|
|
PMXML_NODE b = mxml_subnode(osc, i);
|
|
if (!b)
|
|
break;
|
|
|
|
node = mxml_find_node(b, "TrgLevel1");
|
|
if (!node)
|
|
continue; // node is not a board
|
|
|
|
if (node) m_trgLevel[idx][0] = atof(mxml_get_value(node));
|
|
node = mxml_find_node(b, "TrgLevel2");
|
|
if (node) m_trgLevel[idx][1] = atof(mxml_get_value(node));
|
|
node = mxml_find_node(b, "TrgLevel3");
|
|
if (node) m_trgLevel[idx][2] = atof(mxml_get_value(node));
|
|
node = mxml_find_node(b, "TrgLevel4");
|
|
if (node) m_trgLevel[idx][3] = atof(mxml_get_value(node));
|
|
node = mxml_find_node(b, "TrgMode");
|
|
if (node) m_trgMode[idx] = atoi(mxml_get_value(node));
|
|
node = mxml_find_node(b, "TrgNegative");
|
|
if (node) m_trgNegative[idx] = atoi(mxml_get_value(node)) == 1;
|
|
node = mxml_find_node(b, "TrgDelay");
|
|
if (node) m_trgDelay[idx] = atoi(mxml_get_value(node));
|
|
node = mxml_find_node(b, "TrgConfig");
|
|
if (node) m_trgConfig[idx] = atoi(mxml_get_value(node));
|
|
node = mxml_find_node(b, "HScale");
|
|
if (node) m_HScale[idx] = atoi(mxml_get_value(node));
|
|
node = mxml_find_node(b, "SamplingSpeed");
|
|
if (node) m_reqSamplingSpeed = atof(mxml_get_value(node));
|
|
node = mxml_find_node(b, "FreqLocked");
|
|
if (node) m_freqLocked = atoi(mxml_get_value(node)) == 1;
|
|
node = mxml_find_node(b, "HOffset");
|
|
if (node) m_HOffset[idx] = atoi(mxml_get_value(node));
|
|
|
|
for (j=0 ; j<4 ; j++) {
|
|
char str[256];
|
|
sprintf(str, "ChnOn%d", j);
|
|
node = mxml_find_node(b, str);
|
|
if (node) m_chnOn[idx][j] = atoi(mxml_get_value(node)) == 1;
|
|
sprintf(str, "ChnOffset%d", j);
|
|
node = mxml_find_node(b, str);
|
|
if (node) m_chnOffset[idx][j] = atoi(mxml_get_value(node));
|
|
sprintf(str, "ChnScale%d", j);
|
|
node = mxml_find_node(b, str);
|
|
if (node) m_chnScale[idx][j] = atoi(mxml_get_value(node));
|
|
}
|
|
|
|
node = mxml_find_node(b, "ChnSection");
|
|
if (node) m_chnSection = atoi(mxml_get_value(node));
|
|
|
|
node = mxml_find_node(b, "ClkOn");
|
|
if (node) m_clkOn = atoi(mxml_get_value(node)) == 1;
|
|
|
|
node = mxml_find_node(b, "Range");
|
|
if (node) m_range[idx] = atof(mxml_get_value(node));
|
|
|
|
node = mxml_find_node(b, "SpikeRemoval");
|
|
if (node) m_spikeRemoval = atoi(mxml_get_value(node)) == 1;
|
|
|
|
node = mxml_find_node(b, "ExtRefclk");
|
|
if (node) m_refClk[idx] = atoi(mxml_get_value(node)) == 1;
|
|
|
|
node = mxml_find_node(b, "DisplayScalers");
|
|
if (node) m_displayScalers = atoi(mxml_get_value(node)) == 1;
|
|
|
|
idx++;
|
|
}
|
|
|
|
mxml_free_tree(root);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnSave(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxString filename;
|
|
|
|
if (!m_WFFile && !m_WFfd) {
|
|
filename = wxFileSelector(wxT("Choose a file to write to"), wxEmptyString,
|
|
wxEmptyString, wxT(".xml"), wxT("XML file (*.xml)|*.xml|Binary file (*.dat)|*.dat"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
|
|
if (!filename.empty()) {
|
|
|
|
m_nSaveMax = wxGetNumberFromUser(wxT("Number of events to be saved:"), wxT(""), wxT("DRSOsc"), 1000, 1, 1000000000);
|
|
if (m_nSaveMax > 0) {
|
|
SetSaveBtn(wxT("Close"), wxT("Stop saving waveforms"));
|
|
if (filename.Find(wxT(".xml")) != wxNOT_FOUND) {
|
|
m_WFfd = 0;
|
|
m_WFFile = mxml_open_file(filename.char_str());
|
|
if (m_WFFile)
|
|
mxml_start_element(m_WFFile, "DRSOSC");
|
|
} else {
|
|
m_WFFile = NULL;
|
|
m_WFfd = open(filename.char_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
|
assert(m_WFfd > 0);
|
|
}
|
|
m_osci->SetEventSerial(1);
|
|
m_nSaved = 0;
|
|
}
|
|
}
|
|
} else {
|
|
CloseWFFile(false);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SaveHisto()
|
|
{
|
|
wxString filename;
|
|
|
|
m_osci->Enable(false);
|
|
|
|
filename = wxFileSelector(wxT("Choose a file to write to"), wxEmptyString,
|
|
wxEmptyString, wxT(".txt"), wxT("Text file (*.txt)|*.txt"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
|
|
if (!filename.empty()) {
|
|
|
|
int fd = open(filename.char_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
|
assert(fd > 0);
|
|
|
|
m_screen->SaveHisto(fd);
|
|
|
|
close(fd);
|
|
}
|
|
|
|
m_osci->Enable(true);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
wxPrintDialogData g_printDialogData;
|
|
|
|
void DOFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxPrinter p(&g_printDialogData);
|
|
MyPrintout printout(m_screen, wxT("My printout"));
|
|
if (!p.Print(this, &printout, true)) {
|
|
if (wxPrinter::GetLastError() == wxPRINTER_ERROR)
|
|
wxMessageBox(wxT("There was a problem printing.\nPerhaps your current printer is not set correctly?"), wxT("Printing"), wxOK);
|
|
else
|
|
wxMessageBox(wxT("You cancelled printing"),
|
|
wxT("Printing"), wxOK);
|
|
} else
|
|
g_printDialogData = p.GetPrintDialogData();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
bool MyPrintout::OnPrintPage(int page)
|
|
{
|
|
wxCoord w, h;
|
|
|
|
wxDC *dc = wxPrintout::GetDC();
|
|
if (dc == NULL)
|
|
return false;
|
|
|
|
dc->GetSize(&w, &h);
|
|
FitThisSizeToPage(wxSize(800, 600));
|
|
m_screen->DrawScope(*dc, 800, 600, true);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnConfig( wxCommandEvent& event )
|
|
{
|
|
m_configDialog->Show(true);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnMeasure( wxCommandEvent& event )
|
|
{
|
|
m_measureDialog->Show(true);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnDisplay( wxCommandEvent& event )
|
|
{
|
|
m_displayDialog->Show(true);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnExit( wxCommandEvent& event )
|
|
{
|
|
Close(true);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnAbout( wxCommandEvent& event )
|
|
{
|
|
AboutDialog ad(this);
|
|
ad.ShowModal();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnTrgLevelChange(wxScrollEvent& event)
|
|
{
|
|
double f = (-m_slTrgLevel->GetValue()) / 1000.0; // -0.5 ... 0.5
|
|
|
|
/* convert to voltage according to screen settings */
|
|
int chn = GetTriggerChannel(m_board);
|
|
if (chn > 3)
|
|
chn = 0;
|
|
m_trgLevel[m_board][0] = m_screen->GetScale(m_board, chn)*10*f/1000 + m_screen->GetOffset(m_board, chn);
|
|
m_trgLevel[m_board][1] = m_trgLevel[m_board][0];
|
|
m_trgLevel[m_board][2] = m_trgLevel[m_board][0];
|
|
m_trgLevel[m_board][3] = m_trgLevel[m_board][0];
|
|
m_lastTriggerUpdate = time(NULL);
|
|
m_osci->SetTriggerLevel(m_trgLevel[m_board][0]);
|
|
m_triggerDialog->SetTriggerLevel(m_trgLevel[m_board][chn]);
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetTrgLevel(int i, double value)
|
|
{
|
|
if (i<4) {
|
|
m_trgLevel[m_board][i] = value;
|
|
m_osci->SetIndividualTriggerLevel(i, value);
|
|
}
|
|
m_lastTriggerUpdate = time(NULL);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnTrgDelayChange(wxScrollEvent& event)
|
|
{
|
|
m_trgDelay[m_board] = 100-m_slTrgDelay->GetValue();
|
|
m_osci->SetTriggerDelay(m_trgDelay[m_board]);
|
|
m_trgDelayNs[m_board] = m_osci->GetTriggerDelayNs();
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
double DOFrame::GetTrgPosition(int board)
|
|
{
|
|
// return current trigger position in ns relative to left edge of waveform
|
|
return m_osci->GetWaveformLength() - m_trgDelayNs[board];
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnTrigger(wxCommandEvent& event)
|
|
{
|
|
if (event.GetId() == ID_RUN) {
|
|
if (m_running) {
|
|
m_running = false;
|
|
m_single = false;
|
|
m_osci->SetRunning(false);
|
|
m_osci->SetSingle(false);
|
|
m_btRun->SetLabel(wxT("Run"));
|
|
m_acqPerSecond = 0;
|
|
m_acquisitions = 0;
|
|
m_oldIdle = false;
|
|
} else {
|
|
m_running = true;
|
|
m_single = false;
|
|
m_osci->SetSingle(false);
|
|
m_osci->SetRunning(true);
|
|
m_btRun->SetLabel(wxT("Stop"));
|
|
m_acquisitions = 0;
|
|
m_oldIdle = false;
|
|
m_stopWatch.Start();
|
|
m_stopWatch1.Start();
|
|
}
|
|
} else if (event.GetId() == ID_SINGLE) {
|
|
if (m_running)
|
|
m_osci->SetRunning(false);
|
|
m_running = false;
|
|
m_osci->SetSingle(true);
|
|
m_single = true;
|
|
m_btRun->SetLabel(wxT("Run"));
|
|
|
|
if (m_osci->IsArmed()) {
|
|
/* no trigger happened, so issue a software trigger */
|
|
m_osci->SingleTrigger();
|
|
m_rearm = true;
|
|
} else
|
|
m_osci->Start();
|
|
|
|
m_acqPerSecond = 0;
|
|
m_acquisitions = 0;
|
|
} else if (event.GetId() == ID_TRGCFG) {
|
|
m_triggerDialog->Show();
|
|
}
|
|
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnTrgButton(wxCommandEvent& event)
|
|
{
|
|
if (event.GetId() == ID_TR_NORMAL) {
|
|
m_trgMode[m_board] = TM_NORMAL;
|
|
} else if (event.GetId() == ID_TR_AUTO) {
|
|
m_trgMode[m_board] = TM_AUTO;
|
|
} else if (event.GetId() == ID_TR_POLARITY) {
|
|
m_trgNegative[m_board] = !m_trgNegative[m_board];
|
|
if (m_trgNegative[m_board])
|
|
m_bpPolarity->SetBitmapLabel(wxBitmap(neg_xpm));
|
|
else
|
|
m_bpPolarity->SetBitmapLabel(wxBitmap(pos_xpm));
|
|
} else if (event.GetId() == ID_TR_SOURCE) {
|
|
m_trgConfig[m_board] = (1<<m_rbSource->GetSelection());
|
|
m_triggerDialog->SelectBoard(m_board);
|
|
}
|
|
|
|
m_osci->SetTriggerMode(m_trgMode[m_board]);
|
|
m_osci->SetTriggerConfig(m_trgConfig[m_board]);
|
|
m_osci->SetTriggerPolarity(m_trgNegative[m_board]);
|
|
m_osci->SetTriggerDelay(m_trgDelay[m_board]);
|
|
m_lastTriggerUpdate = time(NULL);
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetTriggerConfig(int b, int config)
|
|
{
|
|
m_trgConfig[b] = config;
|
|
m_rbSource->SetSelection(GetTriggerChannel(b));
|
|
m_osci->SelectBoard(b);
|
|
m_osci->SetTriggerConfig(config);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
int DOFrame::GetTriggerChannel(int b)
|
|
{
|
|
int chn = -1;
|
|
int cfg = m_trgConfig[b];
|
|
|
|
for (int i=0 ; i<5 ; i++)
|
|
if (cfg & (1<<i)) {
|
|
if (chn != -1)
|
|
return 5; // return 5 if several channels set (display "X" in tigger channel)
|
|
chn = i;
|
|
cfg &= ~ (1<<i);
|
|
}
|
|
|
|
if (chn == -1)
|
|
return 5; // return 5 if no trigger selected
|
|
|
|
return chn;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
|
|
void DOFrame::SetTriggerPolarity(int b, bool negative)
|
|
{
|
|
m_trgNegative[b] = negative;
|
|
m_osci->SelectBoard(b);
|
|
m_osci->SetTriggerPolarity(negative);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnChnOn(wxCommandEvent& event)
|
|
{
|
|
int i, id;
|
|
|
|
id = event.GetId();
|
|
|
|
if (id == ID_CHON1) i = 0;
|
|
if (id == ID_CHON2) i = 1;
|
|
if (id == ID_CHON3) i = 2;
|
|
if (id == ID_CHON4) i = 3;
|
|
|
|
m_chnOn[m_board][i] = event.IsChecked();
|
|
m_screen->SetChnOn(m_board, i, event.IsChecked());
|
|
m_osci->SetChnOn(0, i, event.IsChecked());
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnPosChange(wxScrollEvent& event)
|
|
{
|
|
// 2mV per tick -0.5 ... +0.5 V
|
|
m_chnOffset[m_board][0] = m_slPos1->GetValue()*2;
|
|
m_chnOffset[m_board][1] = m_slPos2->GetValue()*2;
|
|
m_chnOffset[m_board][2] = m_slPos3->GetValue()*2;
|
|
m_chnOffset[m_board][3] = m_slPos4->GetValue()*2;
|
|
for (int i=0 ; i<4 ; i++)
|
|
m_screen->SetPos(m_board, i, m_chnOffset[m_board][i]/1000.0);
|
|
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnScaleChange(wxCommandEvent& event)
|
|
{
|
|
int id, i, inc;
|
|
|
|
id = event.GetId();
|
|
|
|
if (id == ID_SCALEUP1) { i=0; inc = -1; }
|
|
if (id == ID_SCALEUP2) { i=1; inc = -1; }
|
|
if (id == ID_SCALEUP3) { i=2; inc = -1; }
|
|
if (id == ID_SCALEUP4) { i=3; inc = -1; }
|
|
|
|
if (id == ID_SCALEDN1) { i=0; inc = +1; }
|
|
if (id == ID_SCALEDN2) { i=1; inc = +1; }
|
|
if (id == ID_SCALEDN3) { i=2; inc = +1; }
|
|
if (id == ID_SCALEDN4) { i=3; inc = +1; }
|
|
|
|
m_chnScale[m_board][i] += inc;
|
|
if (m_chnScale[m_board][i] > 9)
|
|
m_chnScale[m_board][i] = 9;
|
|
if (m_chnScale[m_board][i] < 0)
|
|
m_chnScale[m_board][i] = 0;
|
|
|
|
m_screen->SetScale(m_board, i, m_chnScale[m_board][i]);
|
|
|
|
wxString wxst;
|
|
if (DOScreen::m_scaleTable[m_chnScale[m_board][i]] >= 1000)
|
|
wxst.Printf(wxT("%d V"), DOScreen::m_scaleTable[m_chnScale[m_board][i]]/1000);
|
|
else
|
|
wxst.Printf(wxT("%dmV"), DOScreen::m_scaleTable[m_chnScale[m_board][i]]);
|
|
|
|
if (i == 0) m_stScale1->SetLabel(wxst);
|
|
if (i == 1) m_stScale2->SetLabel(wxst);
|
|
if (i == 2) m_stScale3->SetLabel(wxst);
|
|
if (i == 3) m_stScale4->SetLabel(wxst);
|
|
|
|
m_screen->Refresh();
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::ChangeHScale(int delta)
|
|
{
|
|
// remember current trigger position inside screen
|
|
double trgFrac = (GetTrgPosition(m_board)-m_screen->GetScreenOffset(m_board)) / m_screen->GetScreenSize(m_board);
|
|
|
|
// change screen scale
|
|
if (delta)
|
|
m_screen->SetHScaleInc(m_board, delta < 0 ? -1 : +1);
|
|
m_HScale[m_board] = m_screen->GetHScale(m_board);
|
|
|
|
// adjust sampling speed if necessary
|
|
if (!m_freqLocked) {
|
|
m_reqSamplingSpeed = 100.0/DOScreen::m_hscaleTable[m_HScale[m_board]];
|
|
if (m_reqSamplingSpeed > m_osci->GetMaxSamplingSpeed())
|
|
m_reqSamplingSpeed = m_osci->GetMaxSamplingSpeed();
|
|
if (m_reqSamplingSpeed < m_osci->GetMinSamplingSpeed())
|
|
m_reqSamplingSpeed = m_osci->GetMinSamplingSpeed();
|
|
m_osci->SetSamplingSpeed(m_reqSamplingSpeed);
|
|
}
|
|
|
|
// update config dialog
|
|
if (m_configDialog != NULL)
|
|
m_configDialog->FreqChange();
|
|
|
|
RecalculateHOffset(trgFrac);
|
|
StatReset();
|
|
}
|
|
|
|
void DOFrame::RecalculateHOffset(double trgFrac)
|
|
{
|
|
wxString wxstr;
|
|
|
|
// force recalculation of trigger delay
|
|
m_osci->SetTriggerDelay(m_trgDelay[m_board]);
|
|
m_trgDelayNs[m_board] = m_osci->GetTriggerDelayNs();
|
|
|
|
// calculate new screen offset to keep trigger point at same position
|
|
m_HOffset[m_board] = (int)(GetTrgPosition(m_board) - trgFrac * (double)m_screen->GetScreenSize(m_board) + 0.5);
|
|
|
|
// adjust horizontal slider accordingly
|
|
double v = (m_HOffset[m_board] + m_screen->GetScreenSize(m_board)/2 - m_osci->GetWaveformLength()/2) / m_osci->GetWaveformLength();
|
|
if (v < -0.5) // limit range
|
|
v = -0.5;
|
|
if (v > 0.5)
|
|
v = 0.5;
|
|
m_slHOffset->SetValue((int)(-v*2000 + 0.5));
|
|
|
|
// convert back slider setting to m_HOffset with valid range
|
|
m_HOffset[m_board] = (int)(m_osci->GetWaveformLength()*v - m_screen->GetScreenSize(m_board)/2 + m_osci->GetWaveformLength()/2 + 0.5);
|
|
|
|
m_screen->SetScreenOffset(m_board, m_HOffset[m_board]);
|
|
|
|
// update label
|
|
if (DOScreen::m_hscaleTable[m_HScale[m_board]] >= 1000) {
|
|
wxstr.Printf(wxT("%d us/div"), DOScreen::m_hscaleTable[m_HScale[m_board]]/1000);
|
|
} else {
|
|
wxstr.Printf(wxT("%d ns/div"), DOScreen::m_hscaleTable[m_HScale[m_board]]);
|
|
}
|
|
m_stHScale->SetLabel(wxstr);
|
|
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnHScaleChange(wxCommandEvent& event)
|
|
{
|
|
if (event.GetId() == ID_HSCALEUP)
|
|
ChangeHScale(-1);
|
|
else
|
|
ChangeHScale(+1);
|
|
StatReset();
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnHOffsetChange(wxScrollEvent& event)
|
|
{
|
|
double v = -m_slHOffset->GetValue()/2000.0; // -0.5 ... +0.5
|
|
|
|
// scale from (size/2-length) to (size/2)
|
|
m_HOffset[m_board] = (int)(m_osci->GetWaveformLength()*v - m_screen->GetScreenSize(m_board)/2 + m_osci->GetWaveformLength()/2 + 0.5);
|
|
m_screen->SetScreenOffset(m_board, m_HOffset[m_board]);
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnZero(wxMouseEvent& event)
|
|
{
|
|
if (event.GetId() == ID_HOR_POS) {
|
|
m_slHOffset->SetValue(0);
|
|
OnHOffsetChange((wxScrollEvent&)event);
|
|
}
|
|
if (event.GetId() == ID_TR_LEVEL) {
|
|
m_slTrgLevel->SetValue(0);
|
|
OnTrgLevelChange((wxScrollEvent&)event);
|
|
}
|
|
if (event.GetId() == ID_POS1) {
|
|
m_slPos1->SetValue(0);
|
|
OnPosChange((wxScrollEvent&)event);
|
|
}
|
|
if (event.GetId() == ID_POS2) {
|
|
m_slPos2->SetValue(0);
|
|
OnPosChange((wxScrollEvent&)event);
|
|
}
|
|
if (event.GetId() == ID_POS3) {
|
|
m_slPos3->SetValue(0);
|
|
OnPosChange((wxScrollEvent&)event);
|
|
}
|
|
if (event.GetId() == ID_POS4) {
|
|
m_slPos4->SetValue(0);
|
|
OnPosChange((wxScrollEvent&)event);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayDateTime(bool flag)
|
|
{
|
|
m_screen->SetDisplayDateTime(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayShowGrid(bool flag)
|
|
{
|
|
m_screen->SetDisplayShowGrid(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayLines(bool flag)
|
|
{
|
|
m_screen->SetDisplayLines(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayMode(int mode, int n)
|
|
{
|
|
m_screen->SetDisplayMode(mode, n);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayScalers(bool flag)
|
|
{
|
|
m_displayScalers = flag;
|
|
m_screen->SetDisplayScalers(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayCalibrated(bool flag)
|
|
{
|
|
m_osci->SetCalibrated(flag);
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayCalibrated2(bool flag)
|
|
{
|
|
m_osci->SetCalibrated2(flag);
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayTCalOn(bool flag)
|
|
{
|
|
m_osci->SetTCalOn(flag);
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayTrgCorr(bool flag)
|
|
{
|
|
m_trgCorr = flag;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetRefclk(int b, bool flag)
|
|
{
|
|
m_refClk[b] = flag;
|
|
m_osci->SelectBoard(b);
|
|
m_osci->SetRefclk(b, flag);
|
|
SetSamplingSpeed(m_reqSamplingSpeed);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SelectBoard(int board)
|
|
{
|
|
m_board = board;
|
|
m_configDialog->SelectBoard(board);
|
|
m_triggerDialog->SelectBoard(board);
|
|
ClearWaveforms();
|
|
UpdateControls();
|
|
UpdateStatusBar();
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetMultiBoard(bool flag)
|
|
{
|
|
m_multiBoard = flag;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetSource(int board, int firstChannel, int chnSection)
|
|
{
|
|
m_board = board;
|
|
m_firstChannel = firstChannel;
|
|
m_chnSection = chnSection;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetDisplayRotated(bool flag)
|
|
{
|
|
m_osci->SetRotated(flag);
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::ToggleControls()
|
|
{
|
|
if (m_hideControls) {
|
|
m_pnControls->Show();
|
|
m_hideControls = false;
|
|
} else {
|
|
m_pnControls->Hide();
|
|
m_hideControls = true;
|
|
}
|
|
this->Layout();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnTimer(wxTimerEvent& event)
|
|
{
|
|
char str[256];
|
|
|
|
if (m_first) {
|
|
if (m_osci->GetError(str, sizeof(str)))
|
|
wxMessageBox((const wxChar*)wxString::FromAscii(str),
|
|
wxT("DRS Oscilloscope Error"), wxOK | wxICON_STOP, this);
|
|
|
|
if (m_osci->GetNumberOfBoards() == 0)
|
|
wxMessageBox(wxT("No DRS board found\r\nRunning in demo mode"),
|
|
wxT("DRS Oscilloscope Error"), wxOK | wxICON_STOP, this);
|
|
|
|
if (m_osci->GetNumberOfBoards() &&
|
|
fabs(GetRange() - GetOsci()->GetCalibratedInputRange()) > 0.001) {
|
|
wxString str;
|
|
|
|
str.Printf(wxT("This board was calibrated at %1.2lg V ... %1.2lg V\nYou must recalibrate the board if you use a different input range"),
|
|
GetOsci()->GetCalibratedInputRange()-0.5, GetOsci()->GetCalibratedInputRange()+0.5);
|
|
wxMessageBox(str, wxT("DRS Oscilloscope Warning"), wxOK | wxICON_EXCLAMATION, this);
|
|
}
|
|
|
|
// issue warning if timing calibration not valid
|
|
m_osci->CheckTimingCalibration();
|
|
}
|
|
|
|
m_first = false;
|
|
|
|
/* calculate number of acquistions once per second */
|
|
if (m_osci->GetNumberOfBoards() > 0 && m_stopWatch.Time() > 1000) {
|
|
if (g_epcs)
|
|
g_epcs->Enter();
|
|
m_acqPerSecond = (int) (1000.0 * m_acquisitions / m_stopWatch.Time() + 0.5);
|
|
m_acquisitions = 0;
|
|
if (g_epcs)
|
|
g_epcs->Leave();
|
|
|
|
m_stopWatch.Start();
|
|
|
|
// update temperature and number of acquisitions
|
|
UpdateStatusBar();
|
|
}
|
|
|
|
if (m_epthread == NULL) {
|
|
// handle event processing in the main thread
|
|
if (m_running) {
|
|
if (m_osci->HasNewEvent()) {
|
|
ProcessEvents();
|
|
m_oldIdle = false;
|
|
m_stopWatch1.Start();
|
|
} else {
|
|
if (m_osci->GetTriggerMode() == TM_AUTO && m_stopWatch1.Time() > 1000) {
|
|
m_osci->SingleTrigger();
|
|
while (!m_osci->HasNewEvent());
|
|
m_osci->ReadWaveforms();
|
|
ProcessEvents();
|
|
m_acquisitions++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_single) {
|
|
if (m_osci->HasNewEvent()) {
|
|
ProcessEvents();
|
|
m_oldIdle = false;
|
|
}
|
|
}
|
|
|
|
if (m_osci->IsIdle() && !m_oldIdle) {
|
|
m_oldIdle = true;
|
|
m_screen->Refresh(); // need one refresh to display "TRIG?"
|
|
}
|
|
|
|
m_timer->Start(10, true);
|
|
} else {
|
|
m_screen->Refresh();
|
|
m_timer->Start(40, true);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::ProcessEvents(void)
|
|
{
|
|
int status;
|
|
wxStopWatch sw;
|
|
|
|
while (m_osci->HasNewEvent() && sw.Time() < 100) {
|
|
m_osci->ReadWaveforms();
|
|
if (m_rearm) {
|
|
m_osci->Start();
|
|
m_rearm = false;
|
|
}
|
|
|
|
if (m_trgCorr)
|
|
m_osci->CorrectTriggerPoint(GetTrgPosition(0));
|
|
if (m_WFFile || m_WFfd) {
|
|
status = m_osci->SaveWaveforms(m_WFFile, m_WFfd);
|
|
if (status < 0)
|
|
CloseWFFile(true);
|
|
IncrementSaved();
|
|
if (m_nSaved >= m_nSaveMax)
|
|
CloseWFFile(false);
|
|
}
|
|
|
|
EvaluateMeasurements();
|
|
IncrementAcquisitions();
|
|
|
|
if (m_osci->GetNumberOfBoards() == 0)
|
|
break;
|
|
}
|
|
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
void DOFrame::IncrementAcquisitions()
|
|
{
|
|
if (g_epcs)
|
|
g_epcs->Enter();
|
|
m_acquisitions++;
|
|
if (g_epcs)
|
|
g_epcs->Leave();
|
|
}
|
|
|
|
void DOFrame::IncrementSaved()
|
|
{
|
|
m_nSaved++;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::CloseWFFile(bool errorFlag)
|
|
{
|
|
if (errorFlag)
|
|
wxMessageBox(wxT("Error writing waveforms to file\nWriting will be stopped"),
|
|
wxT("DRS Oscilloscope Error"), wxOK | wxICON_STOP, this);
|
|
|
|
if (g_epcs)
|
|
g_epcs->Enter();
|
|
if (m_WFFile)
|
|
mxml_close_file(m_WFFile);
|
|
if (m_WFfd)
|
|
close(m_WFfd);
|
|
m_WFFile = NULL;
|
|
m_WFfd = 0;
|
|
if (g_epcs)
|
|
g_epcs->Leave();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetSaveBtn(wxString l, wxString t)
|
|
{
|
|
m_btSave->SetLabel(l);
|
|
m_btSave->SetToolTip(t);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::EvaluateMeasurements()
|
|
{
|
|
double x1[2048], y1[2048], x2[2048], y2[2048];
|
|
|
|
double t1 = m_screen->GetT1();
|
|
double t2 = m_screen->GetT2();
|
|
|
|
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
|
|
for (int chn=0 ; chn<4 ; chn++) {
|
|
Measurement *m;
|
|
m = GetMeasurement(idx, chn);
|
|
|
|
int wfIndex;
|
|
if (m_osci->IsMultiBoard())
|
|
wfIndex = m_osci->GetCurrentBoardIndex();
|
|
else
|
|
wfIndex = 0;
|
|
|
|
if (m && m_osci->GetWaveformDepth(chn)) {
|
|
float *wf1 = m_osci->GetWaveform(wfIndex, chn);
|
|
float *wf2 = m_osci->GetWaveform(wfIndex, (chn+1)%4);
|
|
float *time1 = m_osci->GetTime(wfIndex, chn);
|
|
float *time2 = m_osci->GetTime(wfIndex, (chn+1)%4);
|
|
int n_inside = 0;
|
|
|
|
for (int i=0 ; i<m_osci->GetWaveformDepth(chn) ; i++) {
|
|
if (time1[i] >= t1) {
|
|
x1[n_inside] = time1[i];
|
|
y1[n_inside] = wf1[i];
|
|
x2[n_inside] = time2[i];
|
|
y2[n_inside] = wf2[i];
|
|
n_inside++;
|
|
}
|
|
if (time1[i] > t2)
|
|
break;
|
|
}
|
|
|
|
m->Measure(x1, y1, x2, y2, n_inside);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnCursor(wxCommandEvent& event)
|
|
{
|
|
if (event.GetId() == ID_CURSORA) {
|
|
if (m_toggleCursorA->GetValue() == 1) {
|
|
m_cursorA = true;
|
|
m_actCursor = 1;
|
|
} else {
|
|
m_cursorA = false;
|
|
if (m_actCursor == 1)
|
|
m_actCursor = 0;
|
|
}
|
|
} else {
|
|
if (m_toggleCursorB->GetValue() == 1) {
|
|
m_cursorB = true;
|
|
m_actCursor = 2;
|
|
} else {
|
|
m_cursorB = false;
|
|
if (m_actCursor == 2)
|
|
m_actCursor = 0;
|
|
}
|
|
}
|
|
|
|
m_screen->Refresh();
|
|
}
|
|
|
|
void DOFrame::SetCursorA(bool flag)
|
|
{
|
|
m_cursorA = flag;
|
|
m_toggleCursorA->SetValue(flag);
|
|
}
|
|
|
|
void DOFrame::SetCursorB(bool flag)
|
|
{
|
|
m_cursorB = flag;
|
|
m_toggleCursorA->SetValue(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnSnap(wxCommandEvent& event)
|
|
{
|
|
m_snap = event.IsChecked();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetMeasurement(int id, bool flag)
|
|
{
|
|
int m, chn;
|
|
|
|
m = (id - ID_LEVEL1) / 4;
|
|
chn = (id - ID_LEVEL1) % 4;
|
|
|
|
if (m < Measurement::N_MEASUREMENTS) {
|
|
m_measFlag[m][chn] = flag;
|
|
m_measurement[m][chn]->ResetStat();
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetMathDisplay(int id, bool flag)
|
|
{
|
|
m_screen->SetMathDisplay(id, flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetStat(bool flag)
|
|
{
|
|
m_stat = flag;
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetHist(bool flag)
|
|
{
|
|
m_hist = flag;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetStatNStat(int n)
|
|
{
|
|
for (int i=0 ; i<Measurement::N_MEASUREMENTS ; i++)
|
|
for (int j=0 ; j<4 ; j++)
|
|
m_measurement[i][j]->SetNStat(n);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetIndicator(bool flag)
|
|
{
|
|
m_indicator = flag;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
Measurement* DOFrame::GetMeasurement(int m, int chn)
|
|
{
|
|
if (m>=0 && m<Measurement::N_MEASUREMENTS && chn>=0 && chn<4)
|
|
if (m_measFlag[m][chn])
|
|
return m_measurement[m][chn];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::StatReset()
|
|
{
|
|
for (int i=0 ; i<Measurement::N_MEASUREMENTS ; i++)
|
|
for (int j=0 ; j<4 ; j++)
|
|
m_measurement[i][j]->ResetStat();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::SetSamplingSpeed(double speed)
|
|
{
|
|
if (speed > m_osci->GetMaxSamplingSpeed())
|
|
speed = m_osci->GetMaxSamplingSpeed();
|
|
if (speed < m_osci->GetMinSamplingSpeed())
|
|
speed = m_osci->GetMinSamplingSpeed();
|
|
|
|
// remember current trigger position inside screen
|
|
double trgFrac = (GetTrgPosition(m_board)-m_screen->GetScreenOffset(m_board)) / m_screen->GetScreenSize(m_board);
|
|
|
|
m_reqSamplingSpeed = speed;
|
|
m_osci->SetSamplingSpeed(speed);
|
|
|
|
RecalculateHOffset(trgFrac);
|
|
StatReset();
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::EnableTriggerConfig(bool flag)
|
|
{
|
|
m_trgConfigEnabled[m_board] = flag;
|
|
m_btTrgCfg->Enable(flag);
|
|
m_btTrgCfg->Show(flag);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::OnSetTriggerConfig(int id, bool flag)
|
|
{
|
|
int chn;
|
|
|
|
if (id >= ID_OR1 && id <= ID_OREXT) {
|
|
chn = (id - ID_OR1);
|
|
if (flag)
|
|
m_trgConfig[m_board] |= (1 << chn);
|
|
else
|
|
m_trgConfig[m_board] &= ~(1 << chn);
|
|
}
|
|
|
|
if (id >= ID_AND1 && id <= ID_ANDEXT) {
|
|
chn = (id - ID_AND1);
|
|
if (flag)
|
|
m_trgConfig[m_board] |= (1 << (chn+8));
|
|
else
|
|
m_trgConfig[m_board] &= ~(1 << (chn+8));
|
|
}
|
|
|
|
if (id == ID_TRANS) {
|
|
if (flag) {
|
|
// turn on transparent mode for all boards in multi-board mode
|
|
if (m_multiBoard) {
|
|
m_transpTrigger = true;
|
|
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
m_trgConfig[i] |= (1<<15);
|
|
m_trgConfig[i] &= ~((1<<4) | (1<<12)); // remove possible EXT trigger
|
|
}
|
|
} else {
|
|
m_transpTrigger = false;
|
|
m_trgConfig[m_board] |= (1<<15);
|
|
m_trgConfig[m_board] &= ~((1<<4) | (1<<12)); // remove possible EXT trigger
|
|
}
|
|
|
|
// if no channel selected, select first one
|
|
if ((m_trgConfig[m_board] & 0x7FFF) == 0) {
|
|
m_trgConfig[m_board] |= 1;
|
|
DOFrame::SelectBoard(m_board);
|
|
}
|
|
|
|
} else {
|
|
m_transpTrigger = false;
|
|
if (m_multiBoard) {
|
|
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
m_trgConfig[i] &= ~(1<<15);
|
|
if (i > 0)
|
|
m_trgConfig[i] = (1 << 4); // switch back to EXT trigger
|
|
}
|
|
} else
|
|
m_trgConfig[m_board] &= ~(1<<15);
|
|
}
|
|
}
|
|
|
|
m_rbSource->SetSelection(GetTriggerChannel(m_board));
|
|
if (m_multiBoard) {
|
|
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
|
|
m_osci->GetBoard(i)->SetTriggerConfig(m_trgConfig[i]);
|
|
}
|
|
} else {
|
|
m_osci->SetTriggerConfig(m_trgConfig[m_board]);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DOFrame::EnableEPThread(bool flag)
|
|
{
|
|
if (m_epthread)
|
|
m_epthread->Enable(flag);
|
|
}
|