Files
drs4eb/software/drsosc/DOScreen.cpp
T

1872 lines
60 KiB
C++

/*
* doscreen.cpp
* DRS Oscilloscope screen class
* $Id: DOScreen.cpp 22327 2016-10-11 13:18:26Z ritt $
*/
#include "DRSOscInc.h"
/*------------------------------------------------------------------*/
BEGIN_EVENT_TABLE(DOScreen, wxWindow)
EVT_PAINT (DOScreen::OnPaint)
EVT_SIZE (DOScreen::OnSize)
EVT_MOUSE_EVENTS (DOScreen::OnMouse)
EVT_MOUSEWHEEL (DOScreen::OnMouse)
END_EVENT_TABLE()
/*------------------------------------------------------------------*/
const int DOScreen::m_scaleTable[10] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
const int DOScreen::m_hscaleTable[13] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000 };
/*------------------------------------------------------------------*/
DOScreen::DOScreen(wxWindow *parent, Osci *osci, DOFrame *frame)
: wxWindow(parent, wxID_ANY)
{
m_osci = osci;
m_frame = frame;
m_splitMode = 0;
m_paintMode = kPMWaveform;
m_histAxisAuto = true;
m_histAxisMin = m_histAxisMax = 0;
m_dragMin = m_dragMax = false;
m_displayDateTime = false;
m_displayShowGrid = true;
m_displayLines = true;
m_displayScalers = false;
m_displayMode = ID_DISPSAMPLE;
m_displayN = 16;
m_clientWidth = m_clientHeight = 0;
m_mouseX = m_mouseY = 0;
m_MeasX1 = m_MeasX2 = m_MeasY1 = m_MeasY2 = 0;
m_board = 0;
for (int b=0 ; b<MAX_N_BOARDS ; b++) {
m_screenSize[b] = m_screenOffset[b] = 0;
m_hscale[b] = 0;
for (int i=0 ; i<4 ; i++) {
m_chnon[b][i] = false;
m_offset[b][i] = 0;
m_scale[b][i] = 6;
}
}
memset(m_mathFlag, 0, sizeof(m_mathFlag));
m_debugMsg[0] = 0;
// create fonts
#ifdef _MSC_VER
m_fontNormal = wxFont(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
m_fontFixed = wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
m_fontFixedBold = wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
#else
#ifdef __MAC_10_9 // fix for OSX Mavericks
m_fontNormal = wxFont(10, wxFONTFAMILY_DEFAULT,
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxT("LucidaGrande"));
m_fontFixed = wxFont(14, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
m_fontFixedBold = wxFont(14, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
#else
m_fontNormal = wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
m_fontFixed = wxFont(14, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
m_fontFixedBold = wxFont(14, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
#endif
#endif // _MSC_VER
SetBackgroundColour(*wxBLACK);
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
}
/*------------------------------------------------------------------*/
DOScreen::~DOScreen()
{
}
/*------------------------------------------------------------------*/
void DOScreen::OnPaint(wxPaintEvent& event)
{
wxCoord w, h;
// get size form paint DC (buffered paint DC won't work)
wxPaintDC pdc(this);
pdc.GetSize(&w, &h);
m_clientWidth = w;
m_clientHeight = h;
// obtain buffered paint DC to avoid flickering
wxBufferedPaintDC dc(this);
if (m_paintMode == kPMWaveform) {
DrawScope(dc, w, h, false);
DrawMath(dc, w, h, false);
DrawHisto(dc, w, h, false);
} else
DrawTcalib(dc, w, h, false);
// Change "Save" button
if (!m_frame->GetWFfd() && !m_frame->GetWFFile())
m_frame->SetSaveBtn(wxT("Save"), wxT("Save waveforms"));
}
/*------------------------------------------------------------------*/
void DOScreen::DrawDot(wxDC& dc, wxCoord x, wxCoord y, bool printing)
{
if (printing)
dc.DrawRectangle(x, y, 1, 1);
else
dc.DrawPoint(x, y);
}
/*------------------------------------------------------------------*/
bool DOScreen::FindClosestWafeformPoint(int& idx_min, int& x_min, int& y_min)
{
int dist, dist_min, x, y;
// find point on waveform closest to mouse position
idx_min = -1;
dist_min = 1000000;
int b = m_frame->GetCurrentBoard();
wxPoint mpos((int)(m_x1[b]+m_mouseX*(m_x2[b]-m_x1[b])), (int)(m_y1[b]+m_mouseY*(m_y2[b]-m_y1[b])));
for (int idx=0 ; idx<4 ; idx++) {
if (m_chnon[b][idx]) {
if (m_osci->GetWaveformDepth(idx)) {
float *wf = m_frame->GetWaveform(b, idx);
float *time = m_frame->GetTime(b, idx);
for (int i=0 ; i<m_osci->GetWaveformDepth(idx) ; i++) {
x = timeToX(time[i]);
y = voltToY(idx, wf[i]);
dist = (x-mpos.x)*(x-mpos.x) +
(y-mpos.y)*(y-mpos.y);
if (dist < dist_min) {
dist_min = dist;
idx_min = idx;
x_min = x;
y_min = y;
}
}
}
}
}
return dist_min < 2000;
}
/*------------------------------------------------------------------*/
int DOScreen::timeToX(float t)
{
return (int) ((double)(t-m_screenOffset[m_board])/m_screenSize[m_board]*(m_x2[m_board]-m_x1[m_board])+m_x1[m_board] + 0.5);
}
double DOScreen::XToTime(int x)
{
return (double) m_screenSize[m_board]*(x - m_x1[m_board])/(m_x2[m_board]-m_x1[m_board])+m_screenOffset[m_board];
}
double DOScreen::GetT1()
{
return (double) m_screenOffset[m_board];
}
double DOScreen::GetT2()
{
return (double) m_screenSize[m_board]+m_screenOffset[m_board];
}
int DOScreen::voltToY(float v)
{
return voltToY(m_chn, v);
}
int DOScreen::voltToY(int chn, float v)
{
v = v - m_offset[m_board][chn]*1000;
return (int) ((m_y1[m_board]+m_y2[m_board])/2-v/10.0/m_scaleTable[m_scale[m_board][chn]]*(m_y2[m_board]-m_y1[m_board]) + 0.5);
}
double DOScreen::YToVolt(int y)
{
return YToVolt(m_chn, y);
}
double DOScreen::YToVolt(int chn, int y)
{
double v;
v = (((double) m_y1[m_board]+m_y2[m_board])/2 - y)/(m_y2[m_board]-m_y1[m_board])*m_scaleTable[m_scale[m_board][chn]]*10;
v = v + m_offset[m_board][chn]*1000;
return v;
}
/*------------------------------------------------------------------*/
void DOScreen::SetMathDisplay(int id, bool flag)
{
int m, chn;
m = (id - ID_PJ1) / 4;
chn = (id - ID_PJ1) % 4;
m_mathFlag[m][chn] = flag;
}
/*------------------------------------------------------------------*/
void DOScreen::DrawScopeBottom(wxDC& dc, int board, int x1, int y1, int width, bool printing)
{
wxString wxst, wxst2;
int w, h, idx;
wxPoint p[6];
// show voltage per division
for (idx=0 ; idx<4 ; idx++) {
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(m_frame->GetColor(idx, printing));
if (m_chnon[board][idx] && !m_frame->IsFirst()) {
if (m_scaleTable[m_scale[board][idx]] >= 1000)
wxst.Printf(wxT("%d V/div"), m_scaleTable[m_scale[board][idx]]/1000);
else
wxst.Printf(wxT("%d mV/div"), m_scaleTable[m_scale[board][idx]]);
if (m_chnon[board][idx] == 2)
wxst+wxT(" CLK");
dc.GetTextExtent(wxst, &w, &h);
dc.DrawRoundedRectangle(x1 + 10 + idx*80, y1+3, w+10, 15, 2);
dc.DrawText(wxst, x1 + 15 + idx*80, y1+3);
}
}
// show horizontal resolution
if (m_hscaleTable[m_hscale[board]] >= 1000)
wxst.Printf(wxT("%d us/div "), m_hscaleTable[m_hscale[board]]/1000);
else
wxst.Printf(wxT("%d ns/div "), m_hscaleTable[m_hscale[board]]);
if (m_frame->GetActSamplingSpeed() < 1)
wxst2.Printf(wxT("%1.0lf MS/s Calib"), m_frame->GetActSamplingSpeed()*1000);
else
wxst2.Printf(wxT("%1.4lg GS/s Calib"), m_frame->GetActSamplingSpeed());
wxst = wxst+wxst2;
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(*wxGREEN);
dc.SetTextForeground(*wxBLACK);
dc.GetTextExtent(wxst, &w, &h);
dc.DrawRoundedRectangle(width-w, y1+3, w+10, 15, 2);
dc.DrawText(wxst, width+5-w, y1+3);
// cross out calibration if not valid
if (m_frame->GetOsci()->GetNumberOfBoards() > 0) {
if (!m_frame->GetOsci()->IsTCalibrated() || !m_frame->GetOsci()->IsTCalOn()) {
dc.SetPen(wxPen(*wxRED, 1, wxSOLID));
dc.DrawLine(width-22, y1+10, width+6, y1+10);
}
}
// show trigger settings
int x_start = width - w;
if (m_frame->GetTriggerChannel(board) == 5) {
int tc = m_frame->GetTriggerConfig();
wxString wxst1, wxst2;
wxst1.Append((char)wxT('('));
for (int i=0 ; i<5 ; i++)
if (tc & (1<<i)) {
if (i < 4)
wxst1.Append((char) (wxT('1'+i)));
else
wxst1.Append((char) wxT('E'));
wxst1.Append((char) wxT('|'));
}
for (int i=0 ; i<5 ; i++)
if (tc & (1<<(i+8))) {
if (i < 4)
wxst1.Append((char) (wxT('1'+i)));
else
wxst1.Append((char) wxT('E'));
wxst1.Append((char) wxT('&'));
}
if (wxst1.Length() > 0)
wxst1 = wxst1.Left(wxst1.Length()-1);
wxst1.Append((char) wxT(')'));
wxst2.Printf(wxT(" %1.0lf ns"), m_frame->GetTrgDelay());
wxst = wxst1+wxst2;
dc.GetTextExtent(wxst, &w, &h);
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(m_frame->GetColor(4, printing));
dc.DrawRoundedRectangle(x_start-20-w-20, y1+3, w+10+20, 15, 2);
dc.DrawText(wxst, x_start-15-w, y1+3);
} else {
if (m_frame->GetTriggerChannel(board) == 4)
wxst.Printf(wxT("EXT %1.0lf ns"), m_frame->GetTrgDelay());
else
wxst.Printf(wxT("%1.3lf V %1.0lf ns"), m_frame->GetTrgLevel(m_frame->GetTriggerChannel(board)), m_frame->GetTrgDelay());
dc.GetTextExtent(wxst, &w, &h);
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(m_frame->GetColor(m_frame->GetTriggerChannel(board), printing));
dc.DrawRoundedRectangle(x_start-20-w-20, y1+3, w+10+20, 15, 2);
dc.DrawText(wxst, x_start-15-w, y1+3);
}
if (m_frame->GetTrgPolarity() == 0) {
// positive edge
p[0] = wxPoint(0, 11);
p[1] = wxPoint(5, 11);
p[2] = wxPoint(10, 3);
p[3] = wxPoint(15, 3);
} else {
// negative edge
p[0] = wxPoint(0, 3);
p[1] = wxPoint(5, 3);
p[2] = wxPoint(10,11);
p[3] = wxPoint(15,11);
}
dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));
dc.DrawLines(4, p, x_start-20-w-15, y1+3);
dc.SetBrush(*wxGREEN);
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
x_start = x_start - 20 - w - 15;
if (m_osci->IsRunning()) {
wxst.Printf(wxT("%d Acq/s"), m_frame->GetAcqPerSecond());
dc.GetTextExtent(wxst, &w, &h);
dc.DrawRoundedRectangle(x_start-20-w, y1+3, w+10, 15, 2);
dc.DrawText(wxst, x_start-15-w, y1+3);
}
x_start = x_start - 15 - w;
if (m_frame->GetNSaved()) {
wxst.Printf(wxT("%d saved"), m_frame->GetNSaved());
dc.GetTextExtent(wxst, &w, &h);
dc.DrawRoundedRectangle(x_start-20-w, y1+3, w+10, 15, 2);
dc.DrawText(wxst, x_start-15-w, y1+3);
}
}
/*------------------------------------------------------------------*/
void DOScreen::DrawWaveforms(wxDC& dc, int wfIndex, bool printing)
{
int x, y, x_old = 0, y_old = 0, w, h;
wxString wxst;
wxPoint p[6];
dc.DestroyClippingRegion();
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxBLACK_BRUSH);
dc.DrawRectangle(m_x1[m_board], m_y1[m_board], m_x2[m_board]-m_x1[m_board], m_y2[m_board]-m_y1[m_board]);
if (m_splitMode && m_board == m_frame->GetCurrentBoard()) {
dc.SetPen(*wxGREEN_PEN);
dc.DrawRectangle(m_x1[m_board], m_y1[m_board], m_x2[m_board]-m_x1[m_board], m_y2[m_board]-m_y1[m_board]);
dc.DrawRectangle(m_x1[m_board]+1, m_y1[m_board]+1, m_x2[m_board]-m_x1[m_board]-2, m_y2[m_board]-m_y1[m_board]-2);
}
// draw grid
if (m_displayShowGrid) {
dc.SetPen(*wxGREY_PEN);
for (int i=1 ; i<10 ; i++) {
if (i == 5) {
for (int j=m_x1[m_board]+1 ; j<m_x2[m_board] ; j+=2)
DrawDot(dc, j, i*(m_y2[m_board]-m_y1[m_board])/10+m_y1[m_board], printing);
} else {
for (int j=1 ; j<50 ; j++)
DrawDot(dc, m_x1[m_board]+j*(m_x2[m_board]-m_x1[m_board])/50, i*(m_y2[m_board]-m_y1[m_board])/10+m_y1[m_board], printing);
}
}
for (int i=1 ; i<50 ; i++) {
for (int j=-4 ; j<5 ; j+=2)
DrawDot(dc, m_x1[m_board]+i*(m_x2[m_board]-m_x1[m_board])/50, (m_y2[m_board]-m_y1[m_board])/2+m_y1[m_board]+j, printing);
}
for (int i=1 ; i<10 ; i++) {
if (i == 5) {
for (int j=m_y1[m_board]+1 ; j<m_y2[m_board] ; j+=2)
DrawDot(dc, i*(m_x2[m_board]-m_x1[m_board])/10+m_x1[m_board], j, printing);
} else {
for (int j=1 ; j<50 ; j++)
DrawDot(dc, i*(m_x2[m_board]-m_x1[m_board])/10+m_x1[m_board], m_y1[m_board]+j*(m_y2[m_board]-m_y1[m_board])/50, printing);
}
}
for (int i=1 ; i<50 ; i++) {
for (int j=-4 ; j<5 ; j+=2)
DrawDot(dc, (m_x2[m_board]-m_x1[m_board])/2+m_x1[m_board]+j, m_y1[m_board]+i*(m_y2[m_board]-m_y1[m_board])/50, printing);
}
}
for (int idx=3 ; idx>=0 ; idx--) {
if (m_chnon[m_board][idx] && !m_frame->IsFirst()) {
// draw marker
if (m_board == m_frame->GetCurrentBoard()) {
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(m_frame->GetColor(idx, printing));
y = (int) ((m_y1[m_board]+m_y2[m_board])/2+m_offset[m_board][idx]*1000/10.0/m_scaleTable[m_scale[m_board][idx]]*(m_y2[m_board]-m_y1[m_board]) + 0.5);
if (y < m_y1[m_board]) {
wxPoint p[3];
p[0] = wxPoint(10, 0);
p[1] = wxPoint(17, 7);
p[2] = wxPoint( 3, 7);
dc.DrawPolygon(3, p, 0, m_y1[m_board]);
} else if (y > m_y2[m_board]) {
wxPoint p[3];
p[0] = wxPoint(10, 7);
p[1] = wxPoint(17, 0);
p[2] = wxPoint( 3, 0);
dc.DrawPolygon(3, p, 0, m_y2[m_board]-8);
} else {
wxPoint p[7];
p[0] = wxPoint(0, 6);
p[1] = wxPoint(1, 7);
p[2] = wxPoint(12, 7);
p[3] = wxPoint(19, 0);
p[4] = wxPoint(12,-7);
p[5] = wxPoint(1, -7);
p[6] = wxPoint(0, -6);
dc.DrawPolygon(7, p, 0, y);
wxst.Printf(wxT("%d"), idx+1);
dc.GetTextExtent(wxst, &w, &h);
dc.SetTextForeground(*wxBLACK);
dc.SetTextBackground(m_frame->GetColor(idx, printing));
dc.DrawText(wxst, 3, y-h/2);
}
}
// draw waveform
dc.SetClippingRegion(m_x1[m_board]+1, m_y1[m_board]+1, m_x2[m_board]-m_x1[m_board]-2, m_y2[m_board]-m_y1[m_board]-2);
dc.SetPen(wxPen(m_frame->GetColor(idx, printing), 1, wxSOLID));
if (m_osci->GetWaveformDepth(idx)) {
float *wf = m_frame->GetWaveform(wfIndex, idx);
float *time = m_frame->GetTime(wfIndex, idx);
m_chn = idx;
int spacing = timeToX(1/m_osci->GetSamplingSpeed()) - timeToX(0);
for (int i=0 ; i<m_osci->GetWaveformDepth(idx) ; i++) {
x = timeToX(time[i]);
y = voltToY(wf[i]);
if (x >= m_x1[m_board] && x <= m_x2[m_board]) {
if (m_displayLines) {
if (i > 0)
dc.DrawLine(x_old, y_old, x, y);
if (i > 0 && spacing > 5) {
// draw points if separate by more than 5 pixels
dc.DrawRectangle(x-1, y-1, 3, 3);
dc.DrawPoint(x-2, y);
dc.DrawPoint(x+2, y);
dc.DrawPoint(x, y-2);
dc.DrawPoint(x, y+2);
}
} else
DrawDot(dc, x, y, printing);
}
x_old = x;
y_old = y;
}
}
dc.DestroyClippingRegion();
}
}
// draw trigger level
for (int channel=0 ; channel<4 ; channel++) {
if ((m_frame->GetTriggerConfig() & (1 << channel)) ||
(m_frame->GetTriggerConfig() & (1 << (channel+8)))) {
double v = (m_frame->GetTrgLevel(channel) - m_offset[m_board][channel])*1000;
y = (int) ((m_y1[m_board]+m_y2[m_board])/2-(v/10.0/m_scaleTable[m_scale[m_board][channel]]*(m_y2[m_board]-m_y1[m_board]) + 0.5));
p[0] = wxPoint(-8, 0);
p[1] = wxPoint( 0, -5);
p[2] = wxPoint( 0, 5);
dc.SetBrush(m_frame->GetColor(channel, printing));
dc.SetPen(m_frame->GetColor(channel, printing));
dc.DrawPolygon(3, p, m_x2[m_board]-2, y);
if (time(NULL) - m_frame->GetLastTriggerUpdate() < 2 && !m_frame->IsFirst()) {
dc.DrawLine(m_x1[m_board], y, m_x2[m_board]-2, y);
}
}
}
// draw trigger horizontal position marker
p[0] = wxPoint(-5, 0);
p[1] = wxPoint( 4, 0);
p[2] = wxPoint( 4, 7);
p[3] = wxPoint( 0, 11);
p[4] = wxPoint( -1, 11);
p[5] = wxPoint(-5, 7);
dc.SetBrush(m_frame->GetColor(m_frame->GetTriggerChannel(m_board), printing));
dc.SetPen(m_frame->GetColor(m_frame->GetTriggerChannel(m_board), printing));
dc.DrawPolygon(6, p, (wxCoord)((m_frame->GetTrgPosition(m_board)-GetScreenOffset(m_board)) / GetScreenSize(m_board) * (m_x2[m_board]-m_x1[m_board]) + m_x1[m_board]),
(wxCoord)m_y1[m_board]);
wxst = wxT("T");
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(m_frame->GetColor(m_frame->GetTriggerChannel(m_board), printing));
dc.SetTextForeground(*wxBLACK);
dc.GetTextExtent(wxst, &w, &h);
dc.DrawText(wxst, (wxCoord)((m_frame->GetTrgPosition(m_board)-GetScreenOffset(m_board)) / GetScreenSize(m_board) * (m_x2[m_board]-m_x1[m_board]) + m_x1[m_board] - w/2 - 1),
(wxCoord)(m_y1[m_board]));
}
/*------------------------------------------------------------------*/
void DOScreen::DrawScope(wxDC& dc, wxCoord width, wxCoord height, bool printing)
{
int x, y, w, h, y_top, n;
int idx_min, x_min, y_min;
wxString wxst, wxst2;
if (m_frame->GetOsci()->SkipDisplay())
return;
// tell DOFrame to pull new waveforms from EPThread
m_frame->UpdateWaveforms();
m_dc = &dc;
// scope area
m_sx1 = 20;
m_sy1 = 1;
m_sx2 = width-1;
m_sy2 = height-20;
// if histo display is on, only show waveform in upper half
if (m_frame->IsHist())
m_sy2 = height/2-20;
// waveform area
m_x1[m_board] = m_sx1;
m_y1[m_board] = m_sy1;
m_x2[m_board] = m_sx2;
m_y2[m_board] = m_sy2;
y_top = 1;
dc.SetFont(m_fontNormal);
// draw overall frame
if (printing) {
dc.SetBackground(*wxWHITE_BRUSH);
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
} else {
dc.SetBackground(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(*wxBLACK_BRUSH);
}
//static int n_event = 0;
//if (++n_event % 30 == 0) {
if (m_frame->IsHist())
dc.DrawRectangle(0, 0, width, height/2);
else
dc.DrawRectangle(0, 0, width, height);
//}
DrawScopeBottom(dc, m_frame->GetCurrentBoard(), 20, m_sy2, width-20, printing);
if (m_splitMode) {
n = m_osci->GetNumberOfBoards();
w = (m_sx2-m_sx1)/2;
h = (m_sy2-m_sy1) / (((n-1) / 2)+1);
for (int i=0 ; i<n ; i++) {
m_x1[i] = m_sx1+(i%2)*w;
m_y1[i] = m_sy1+(i/2)*h;
m_x2[i] = m_x1[i]+w-((i+1)%2);
m_y2[i] = m_y1[i]+h;
m_board = i;
DrawWaveforms(dc, i, printing);
}
} else {
m_board = m_frame->GetCurrentBoard();
m_x1[m_board] = m_sx1;
m_y1[m_board] = m_sy1;
m_x2[m_board] = m_sx2;
m_y2[m_board] = m_sy2;
int wfIndex;
if (m_osci->IsMultiBoard())
wfIndex = m_osci->GetCurrentBoardIndex();
else
wfIndex = 0;
DrawWaveforms(dc, wfIndex, printing);
}
// display optional debug messages
if (*m_frame->GetOsci()->GetDebugMsg()) {
wxst = wxString((const wxChar *)m_frame->GetOsci()->GetDebugMsg());
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(*wxGREEN);
dc.SetTextForeground(*wxBLACK);
dc.GetTextExtent(wxst, &w, &h);
dc.DrawRoundedRectangle(m_x1[m_board]+2, m_sy1+2, w+5, 15, 2);
dc.DrawText(wxst, m_sx1+4, m_sy1+2);
}
if (m_debugMsg[0]) {
wxst = wxString((const wxChar *)m_debugMsg);
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetBrush(*wxGREEN);
dc.SetTextForeground(*wxBLACK);
dc.GetTextExtent(wxst, &w, &h);
dc.DrawRoundedRectangle(m_sx1+2, m_sy1+2, w+5, 15, 2);
dc.DrawText(wxst, m_sx1+4, m_sy1+2);
}
// print "TRIG?" or "AUTO" if no recent trigger
if (m_osci->GetNumberOfBoards() && m_osci->IsIdle()) {
dc.SetTextForeground(*wxGREEN);
if (m_osci->GetTriggerMode() == TM_AUTO)
wxst = wxT("AUTO");
else
wxst = wxT("TRIG?");
dc.GetTextExtent(wxst, &w, &h);
if (m_osci->GetNumberOfBoards() > 1)
dc.DrawText(wxst, m_x2[m_board] - w - 5, m_y1[m_board] + 22);
else
dc.DrawText(wxst, m_x2[m_board] - w - 5, m_y1[m_board] + 1);
}
// display date/time
if (m_displayDateTime) {
dc.SetTextForeground(*wxGREEN);
wxst.Printf(wxT("%s"),wxDateTime::Now().Format(wxT("%c")).c_str());
dc.GetTextExtent(wxst, &w, &h);
dc.DrawText(wxst, m_x2[m_board] - w - 2, m_y2[m_board] - h - 1);
}
// display board selector buttons
n = m_osci->GetNumberOfBoards();
if (n > 1) {
if (m_osci->IsMultiBoard())
n++;
for (int i=0 ; i<n ; i++) {
m_BSX1[i] = m_sx2-20*(n-i);
m_BSY1[i] = m_sy1+4;
m_BSX2[i] = m_BSX1[i]+16;
m_BSY2[i] = m_BSY1[i]+16;
if (m_osci->IsMultiBoard() && i == n-1) {
// display cross icon
dc.SetPen(wxPen(*wxGREEN, 1, wxSOLID));
if (m_splitMode) {
dc.SetBrush(*wxGREEN);
dc.DrawRoundedRectangle(m_BSX1[i], m_BSY1[i], 16, 16, 2);
dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));
} else {
dc.SetBrush(*wxBLACK);
dc.DrawRoundedRectangle(m_BSX1[i], m_BSY1[i], 16, 16, 2);
dc.SetPen(wxPen(*wxGREEN, 1, wxSOLID));
}
dc.DrawLine(m_BSX1[i]+8, m_BSY1[i], m_BSX1[i]+8, m_BSY2[i]);
dc.DrawLine(m_BSX1[i], m_BSY1[i]+8, m_BSX2[i], m_BSY1[i]+8);
} else {
// display board number
wxst.Printf(wxT("%d"), i+1);
if (i == m_osci->GetCurrentBoardIndex() && !m_splitMode) {
dc.SetPen(wxPen(*wxGREEN, 1, wxSOLID));
dc.SetBrush(*wxGREEN);
dc.SetTextForeground(*wxBLACK);
} else {
dc.SetPen(wxPen(*wxGREEN, 1, wxSOLID));
dc.SetBrush(*wxBLACK);
dc.SetTextForeground(*wxGREEN);
}
dc.DrawRoundedRectangle(m_BSX1[i], m_BSY1[i], 16, 16, 2);
dc.DrawText(wxst, m_BSX1[i]+4, m_BSY1[i]+2);
}
}
}
// display cursors and measurements only for current board
m_board = m_frame->GetCurrentBoard();
// display cursor
if (width > 0 && height > 0) {
int b = m_board;
wxPoint mpos((int)(m_x1[b]+m_mouseX*(m_x2[b]-m_x1[b])), (int)(m_y1[b]+m_mouseY*(m_y2[b]-m_y1[b])));
if (m_frame->IsCursorA() || m_frame->IsCursorB()) {
// find point on waveform closest to mouse position
FindClosestWafeformPoint(idx_min, x_min, y_min);
if (m_frame->IsSnap()) {
x = x_min;
y = y_min;
} else {
x = mpos.x;
y = mpos.y;
}
if (m_frame->ActiveCursor() == 1) {
m_idxA = idx_min;
m_xCursorA = (double)(x - m_x1[b])/(m_x2[b]-m_x1[b]);
m_yCursorA = (double)(y - m_y1[b])/(m_y2[b]-m_y1[b]);
m_uCursorA = YToVolt(y);
m_tCursorA = XToTime(x);
} else if (m_frame->ActiveCursor() == 2) {
m_idxB = idx_min;
m_xCursorB = (double)(x - m_x1[b])/(m_x2[b]-m_x1[b]);
m_yCursorB = (double)(y - m_y1[b])/(m_y2[b]-m_y1[b]);
m_uCursorB = YToVolt(y);
m_tCursorB = XToTime(x);
}
// draw cursor A
if (m_frame->IsCursorA() && (m_frame->ActiveCursor() != 1 || (m_mouseX > 0 && m_mouseX < 1 && m_mouseY > 0 && m_mouseY < 1))) {
dc.SetPen(wxPen(m_frame->GetColor(m_idxA, printing), 1, wxSHORT_DASH));
int x = (int)(m_x1[b]+m_xCursorA*(m_x2[b]-m_x1[b]));
int y = (int)(m_y1[b]+m_yCursorA*(m_y2[b]-m_y1[b]));
dc.DrawLine(x, m_y1[b], x, m_y2[b]);
dc.DrawLine(m_x1[b], y, m_x2[b], y);
dc.DrawLine(x-3, y, x, y+3);
dc.DrawLine(x, y+3, x+3, y);
dc.DrawLine(x+3, y, x, y-3);
dc.DrawLine(x, y-3, x-3, y);
dc.SetTextForeground(*wxGREEN);
dc.GetTextExtent(wxT("Cursor A:"), &w, &h);
dc.DrawText(wxT("Cursor A:"), m_x1[b] + 3, y_top);
wxString str;
str.Printf(wxT("%1.1lf ns / %1.1lf mV"), m_tCursorA, m_uCursorA);
dc.SetTextForeground(m_frame->GetColor(m_idxA, printing));
dc.DrawText(str, m_x1[b] + w + 10, y_top);
y_top += h;
}
// draw cursor B
if (m_frame->IsCursorB() && (m_frame->ActiveCursor() != 2 || (m_mouseX > 0 && m_mouseX < 1 && m_mouseY > 0 && m_mouseY < 1))) {
dc.SetPen(wxPen(m_frame->GetColor(m_idxB, printing), 1, wxDOT));
int x = (int)(m_x1[b]+m_xCursorB*(m_x2[b]-m_x1[b]));
int y = (int)(m_y1[b]+m_yCursorB*(m_y2[b]-m_y1[b]));
dc.DrawLine(x, m_y1[b], x, m_y2[b]);
dc.DrawLine(m_x1[b], y, m_x2[b], y);
dc.DrawLine(x-3, y, x, y+3);
dc.DrawLine(x, y+3, x+3, y);
dc.DrawLine(x+3, y, x, y-3);
dc.DrawLine(x, y-3, x-3, y);
dc.SetTextForeground(*wxGREEN);
dc.GetTextExtent(wxT("Cursor B:"), &w, &h);
dc.DrawText(wxT("Cursor B:"), m_x1[b] + 3, y_top);
wxString str;
str.Printf(wxT("%1.1lf ns / %1.1lf mV"), m_tCursorB, m_uCursorB);
dc.SetTextForeground(m_frame->GetColor(m_idxB, printing));
dc.DrawText(str, m_x1[b] + w + 10, y_top);
y_top += h;
}
// cursor difference
if (m_frame->IsCursorA() && m_frame->IsCursorB()) {
dc.SetTextForeground(*wxGREEN);
dc.GetTextExtent(wxT("Diff:"), &w, &h);
dc.DrawText(wxT("Diff:"), m_x1[b] + 3, y_top);
wxString str;
str.Printf(wxT("%1.3lf ns / %1.1lf mV"), m_tCursorB - m_tCursorA, m_uCursorB - m_uCursorA);
dc.DrawText(str, m_x1[b] + w + 10, y_top);
y_top += h;
}
y_top += h; // leave some space
}
}
// count measurements
for (int idx = n = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
if (m_frame->GetMeasurement(idx, chn) != NULL)
n++;
}
}
// display measurements
dc.SetFont(m_fontFixed);
dc.GetTextExtent(wxT("Chn delay [CH1]: "), &w, &h);
int nameWidth = w;
dc.GetTextExtent(wxT("-00.000 MHz"), &w, &h);
int valueWidth = w;
if (m_frame->IsStat() && n > 0) {
dc.SetTextForeground(*wxGREEN);
dc.DrawText(wxT(" Min Max Mean Std N"), m_x1[m_board]+nameWidth+valueWidth, y_top);
dc.GetTextExtent(wxT(" Min Max Mean Std N"), &w, &h);
m_MeasX1 = m_x1[m_board] + nameWidth + valueWidth;
m_MeasX2 = m_MeasX1 + w;
y_top += h;
}
m_MeasY1 = y_top;
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
Measurement *m;
m = m_frame->GetMeasurement(idx, chn);
m_chn = chn;
if (m != NULL) {
// set parameters from cursor positions
m->SetParam(0, m_tCursorA);
m->SetParam(1, m_uCursorA);
m->SetParam(2, m_tCursorB);
m->SetParam(3, m_uCursorB);
dc.SetTextForeground(m_frame->GetColor(chn, printing));
wxString str;
str.Printf(wxT("%s [CH%d]:"), m_frame->GetMeasurementName(idx).c_str(), chn+1);
dc.DrawText(str, m_x1[m_board] + 3, y_top);
double x1[2048], y1[2048], x2[2048], y2[2048];
int wfIndex;
if (m_osci->IsMultiBoard())
wfIndex = m_osci->GetCurrentBoardIndex();
else
wfIndex = 0;
if (m_osci->GetWaveformDepth(chn)) {
float *wf1 = m_frame->GetWaveform(wfIndex, chn);
float *wf2 = m_frame->GetWaveform(wfIndex, (chn+1)%4);
float *time1 = m_frame->GetTime(wfIndex, chn);
float *time2 = m_frame->GetTime(wfIndex, (chn+1)%4);
int n_inside = 0;
for (int i=0 ; i<m_osci->GetWaveformDepth(chn) ; i++) {
if (timeToX(time1[i]) >= m_x1[m_board]) {
x1[n_inside] = time1[i];
y1[n_inside] = wf1[i];
x2[n_inside] = time2[i];
y2[n_inside] = wf2[i];
n_inside++;
}
if (timeToX(time1[i]) > m_x2[m_board])
break;
}
dc.SetPen(wxPen(m_frame->GetColor(chn, printing), 1, wxSOLID));
m->Measure(x1, y1, x2, y2, n_inside, false, m_frame->IsIndicator() && m_chnon[m_board][chn] ? this : NULL);
dc.DrawText(m->GetString(), m_x1[m_board]+nameWidth, y_top+1);
if (m_frame->IsStat()) {
dc.DrawText(m->GetStat(), m_x1[m_board]+nameWidth+valueWidth, y_top+1);
}
}
y_top += h;
}
}
}
m_MeasY2 = y_top;
// display scalers
if (m_displayScalers) {
y_top += 5;
for (int chn=0 ; chn<5 ; chn++) {
if (chn == 4)
dc.SetTextForeground(*wxLIGHT_GREY);
else
dc.SetTextForeground(m_frame->GetColor(chn, printing));
unsigned int s = m_osci->GetScaler(chn);
if (chn == 4) {
if (s < 1000)
wxst.Printf(wxT("FreqT: %d Hz"), s);
else if (s < 1000000)
wxst.Printf(wxT("FreqT: %1.3lf kHz"), s/1000.0);
else
wxst.Printf(wxT("FreqT: %1.3lf MHz"), s/1000000.0);
} else {
if (s < 1000)
wxst.Printf(wxT("Freq%d: %d Hz"), chn+1, s);
else if (s < 1000000)
wxst.Printf(wxT("Freq%d: %1.3lf kHz"), chn+1, s/1000.0);
else
wxst.Printf(wxT("Freq%d: %1.3lf MHz"), chn+1, s/1000000.0);
}
dc.GetTextExtent(wxst, &w, &h);
dc.DrawText(wxst, m_x1[m_board] + 3, y_top);
y_top += h;
}
}
dc.DestroyClippingRegion();
}
/*------------------------------------------------------------------*/
void DOScreen::DrawHisto(wxDC& dc, wxCoord width, wxCoord height, bool printing)
{
int i, x, y, x_old, y_old, w, h, y_top;
wxString wxst, wxst2;
int histo[1000], uflow, oflow;
if (m_frame->GetOsci()->SkipDisplay())
return;
if (!m_frame->IsHist())
return;
m_dc = &dc;
// histo area
m_hx1 = 20;
m_hy1 = height/2+1;
m_hx2 = width-1;
m_hy2 = height-20;
x_old = y_old = 0;
y_top = 1;
/* if all waveform channels are off, use full screen */
if (!m_chnon[m_board][0] && !m_chnon[m_board][1] && !m_chnon[m_board][2] && !m_chnon[m_board][3])
m_sy1 = 1;
// set font for all text output
dc.SetFont(m_fontFixedBold);
// draw overall frame
if (printing) {
dc.SetBackground(*wxWHITE_BRUSH);
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
} else {
dc.SetBackground(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(*wxBLACK_BRUSH);
}
dc.DrawRectangle(0, height/2, width, height/2);
dc.SetPen(*wxGREY_PEN);
dc.DrawRectangle(m_hx1, m_hy1, m_hx2-m_hx1, m_hy2-m_hy1);
if (m_histAxisAuto) {
bool first = true;
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
Measurement *m = m_frame->GetMeasurement(idx, chn);
if (m == NULL)
continue;
/* find min and max of array */
double *a = m->GetArray();
int n = m->GetNMeasured();
if (first) {
m_histAxisMin = a[0];
m_histAxisMax = a[0];
first = false;
}
for (i=1 ; i<n ; i++) {
if (a[i] < m_histAxisMin)
m_histAxisMin = a[i];
if (a[i] > m_histAxisMax)
m_histAxisMax = a[i];
}
}
}
}
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
Measurement *m = m_frame->GetMeasurement(idx, chn);
if (m == NULL)
continue;
/* build histogram */
double *a = m->GetArray();
int n = m->GetNMeasured();
int nBins = (int) (1.5*sqrt((double)n));
if (nBins > 1000)
nBins = 1000;
for (i=0 ; i<nBins ; i++)
histo[i] = 0;
uflow = oflow = 0;
/* fill data into histo */
for (i=0 ; i<n ; i++) {
int bin = (int)((a[i]-m_histAxisMin)/(m_histAxisMax-m_histAxisMin)*(nBins-1));
if (bin >= nBins)
oflow++;
else if (bin < 0)
uflow++;
else
histo[bin]++;
}
int hmax = histo[0];
for (i=1 ; i<nBins ; i++) {
if (histo[i] > hmax)
hmax = histo[i];
}
/* draw histo */
dc.SetPen(wxPen(m_frame->GetColor(chn, printing), 1, wxSOLID));
for (i=0 ; i<nBins ; i++) {
x = m_hx1+(int)((double)i/nBins*(m_hx2-m_hx1));
y = m_hy2-(int)((double)histo[i]/hmax*(m_hy2-m_hy1-30));
if (i>0) {
dc.DrawLine(x_old, y_old, x, y_old);
dc.DrawLine(x, y_old, x, y);
}
x_old = x;
y_old = y;
}
dc.DrawLine(x_old, y_old, m_hx2, y_old);
// underflow and overflow bins
dc.SetBrush(wxBrush(m_frame->GetColor(chn, printing)));
if (uflow) {
y = (int)((double)uflow/hmax*(m_hy2-m_hy1-1));
if (y > m_hy2-m_hy1-1)
y = m_hy2-m_hy1-1;
dc.DrawRectangle(m_hx1, m_hy2-y, 3, y);
}
if (oflow) {
y = (int)((double)oflow/hmax*(m_hy2-m_hy1-1));
if (y > m_hy2-m_hy1-1)
y = m_hy2-m_hy1-1;
dc.DrawRectangle(m_hx2-3, m_hy2-y, 3, y);
}
dc.SetBrush(*wxBLACK_BRUSH);
}
}
DrawHAxis(dc, m_hx1, m_hy2, m_hx2-m_hx1, 3, 4, 5, 7, 0, m_histAxisMin, m_histAxisMax);
// display statistics
dc.SetFont(m_fontFixed);
y_top = m_hy1 + 1;
if (m_frame->IsStat()) {
dc.SetTextForeground(*wxGREEN);
dc.DrawText(wxT(" Min Max Mean Std N"), m_hx1, y_top);
dc.GetTextExtent(wxT("N"), &w, &h);
y_top += h;
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
Measurement *m = m_frame->GetMeasurement(idx, chn);
if (m == NULL)
continue;
double *a = m->GetArray();
int nValues = m->GetNMeasured();
double sa = 0;
double sa2 = 0;
int n = 0;
double mean = 0;
double std = 0;
for (i=0 ; i<nValues ; i++) {
if (a[i] >= m_histAxisMin && a[i] <= m_histAxisMax) {
sa += a[i];
sa2 += a[i]*a[i];
n++;
}
}
if (n) {
mean = sa / n;
std = sqrt(sa2/n - sa*sa/n/n);
}
wxString str;
if (n == 0)
str.Printf(wxT(" N/A N/A N/A N/A %6d"), 0);
else
str.Printf(wxT("%8.3lf %8.3lf %8.3lf %8.4lf %6d"), m_histAxisMin,
m_histAxisMax, mean, std, n);
dc.SetTextForeground(m_frame->GetColor(chn, printing));
dc.DrawText(str, m_hx1, y_top);
y_top += h;
}
}
}
dc.SetPen(*wxGREY_PEN);
if (m_dragMin) {
x = (int) ((m_minCursor - m_histAxisMin) / (m_histAxisMax - m_histAxisMin) * (m_hx2-m_hx1) + m_hx1);
dc.DrawLine(x, m_hy1, x, m_hy2);
} else
x = m_hx1;
// dragging handles
y = (m_hy1+m_hy2)/2;
dc.DrawLine(x, y-10, x+10, y-10);
dc.DrawEllipticArc(x+5, y-10, 10, 10, 0, 90);
dc.DrawLine(x+15, y-5, x+15, y+5);
dc.DrawEllipticArc(x+5, y, 10, 10, 270, 360);
dc.DrawLine(x, y+10, x+10, y+10);
dc.DrawLine(x+5, y-6, x+5, y+6);
dc.DrawLine(x+10, y-6, x+10, y+6);
if (m_dragMax) {
x = (int) ((m_maxCursor - m_histAxisMin) / (m_histAxisMax - m_histAxisMin) * (m_hx2-m_hx1) + m_hx1);
dc.DrawLine(x, m_hy1, x, m_hy2);
} else
x = m_hx2;
y = (m_hy1+m_hy2)/2;
dc.DrawLine(x, y-10, x-10, y-10);
dc.DrawEllipticArc(x-15, y-10, 10, 10, 90, 180);
dc.DrawLine(x-15, y-5, x-15, y+5);
dc.DrawEllipticArc(x-15, y, 10, 10, 180, 270);
dc.DrawLine(x, y+10, x-10, y+10);
dc.DrawLine(x-5, y-6, x-5, y+6);
dc.DrawLine(x-10, y-6, x-10, y+6);
// zoom out box
if (!m_histAxisAuto) {
dc.DrawRoundedRectangle((m_hx1+m_hx2)/2-15, m_hy2-10, 30, 14, 5);
dc.DrawLine((m_hx1+m_hx2)/2-10, m_hy2-3, (m_hx1+m_hx2)/2+10, m_hy2-3);
dc.DrawLine((m_hx1+m_hx2)/2-10, m_hy2-3, (m_hx1+m_hx2)/2-6, m_hy2-7);
dc.DrawLine((m_hx1+m_hx2)/2-10, m_hy2-3, (m_hx1+m_hx2)/2-6, m_hy2+1);
dc.DrawLine((m_hx1+m_hx2)/2+10, m_hy2-3, (m_hx1+m_hx2)/2+6, m_hy2-7);
dc.DrawLine((m_hx1+m_hx2)/2+10, m_hy2-3, (m_hx1+m_hx2)/2+6, m_hy2+1);
}
// save button
wxString wxs("Save");
dc.GetTextExtent(wxs, &w, &h);
m_savex1 = m_hx2-w-8;
m_savey1 = m_hy1+4;
m_savex2 = m_hx2-4;
m_savey2 = m_savey1+h+2;
dc.SetPen(wxPen(*wxGREEN, 1, wxSOLID));
dc.SetBrush(*wxBLACK);
dc.SetTextForeground(*wxGREEN);
dc.DrawRoundedRectangle(m_savex1, m_savey1, m_savex2-m_savex1, m_savey2-m_savey1, 2);
dc.DrawText(wxs, m_savex1+2, m_savey1+2);
}
/*------------------------------------------------------------------*/
void DOScreen::SaveHisto(int fh)
{
int i;
wxString wxst, wxst2;
int histo[1000], uflow, oflow;
double mmin, mmax;
if (m_histAxisAuto) {
bool first = true;
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
Measurement *m = m_frame->GetMeasurement(idx, chn);
if (m == NULL)
continue;
/* find min and max of array */
double *a = m->GetArray();
int n = m->GetNMeasured();
if (first) {
m_histAxisMin = a[0];
m_histAxisMax = a[0];
first = false;
}
for (i=1 ; i<n ; i++) {
if (a[i] < m_histAxisMin)
m_histAxisMin = a[i];
if (a[i] > m_histAxisMax)
m_histAxisMax = a[i];
}
}
}
}
for (int idx = 0 ; idx<Measurement::N_MEASUREMENTS ; idx++) {
for (int chn=0 ; chn<4 ; chn++) {
Measurement *m = m_frame->GetMeasurement(idx, chn);
if (m == NULL)
continue;
wxst.Printf(wxT("%s [CH%d]\r\n\r\n"), m_frame->GetMeasurementName(idx).c_str(), chn+1);
write(fh, wxst.c_str(), wxst.length());
/* build histogram */
double *a = m->GetArray();
int n = m->GetNMeasured();
int nBins = (int) (1.5*sqrt((double)n));
if (nBins > 1000)
nBins = 1000;
for (i=0 ; i<nBins ; i++)
histo[i] = 0;
uflow = oflow = 0;
/* fill data into histo */
mmin = mmax = a[0];
for (i=0 ; i<n ; i++) {
int bin = (int)((a[i]-m_histAxisMin)/(m_histAxisMax-m_histAxisMin)*(nBins-1));
if (bin >= nBins)
oflow++;
else if (bin < 0)
uflow++;
else
histo[bin]++;
if (a[i] > mmax)
mmax = a[i];
if (a[i] < mmax)
mmin = a[i];
}
int hmax = histo[0];
for (i=1 ; i<nBins ; i++) {
if (histo[i] > hmax)
hmax = histo[i];
}
if (uflow) {
wxst.Printf(wxT("%8.3lf\t%8.3lf\t%d\r\n"), mmin, m_histAxisMin, uflow);
write(fh, wxst.c_str(), wxst.length());
}
/* save histo */
for (i=0 ; i<nBins ; i++) {
double x1 = (double)i/(nBins-1)*(m_histAxisMax-m_histAxisMin)+m_histAxisMin;
double x2 = (double)(i+1)/(nBins-1)*(m_histAxisMax-m_histAxisMin)+m_histAxisMin;
wxst.Printf(wxT("%8.3lf\t%8.3lf\t%d\r\n"), x1, x2, histo[i]);
write(fh, wxst.c_str(), wxst.length());
}
if (oflow) {
wxst.Printf(wxT("%8.3lf\t%8.3lf\t%d\r\n"), m_histAxisMax, mmax, oflow);
write(fh, wxst.c_str(), wxst.length());
}
wxst.Printf(wxT("\r\n\r\n"));
write(fh, wxst.c_str(), wxst.length());
}
}
}
/*------------------------------------------------------------------*/
#define LN10 2.302585094
#define LOG2 0.301029996
#define LOG5 0.698970005
/* min/max/abs macros */
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
void DOScreen::DrawHAxis(wxDC &dc, int x1, int y1, int width,
int minor, int major, int text, int label, int grid, double xmin, double xmax)
{
double dx, int_dx, frac_dx, x_act, label_dx, major_dx, x_screen, maxwidth;
int tick_base, major_base, label_base, n_sig1, n_sig2, xs, w, h;
wxString str;
double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
if (xmax <= xmin || width <= 0)
return;
/* use 5 as min tick distance */
dx = (xmax - xmin) / (double) (width / 5);
frac_dx = modf(log(dx) / LN10, &int_dx);
if (frac_dx < 0) {
frac_dx += 1;
int_dx -= 1;
}
tick_base = frac_dx < LOG2 ? 1 : frac_dx < LOG5 ? 2 : 3;
major_base = label_base = tick_base + 1;
/* rounding up of dx, label_dx */
dx = pow(10, int_dx) * base[tick_base];
major_dx = pow(10, int_dx) * base[major_base];
label_dx = major_dx;
/* number of significant digits */
if (xmin == 0)
n_sig1 = 0;
else
n_sig1 = (int) floor(log(fabs(xmin)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
if (xmax == 0)
n_sig2 = 0;
else
n_sig2 =
(int) floor(log(fabs(xmax)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
n_sig1 = MAX(n_sig1, n_sig2);
n_sig1 = MAX(n_sig1, 4);
/* determination of maximal width of labels */
str.Printf(wxT("%1.*lG"), n_sig1, floor(xmin / dx) * dx);
dc.GetTextExtent(str, &w, &h);
maxwidth = h / 2 * str.Len();
str.Printf(wxT("%1.*lG"), n_sig1, floor(xmax / dx) * dx);
maxwidth = MAX(maxwidth, h / 2 * str.Len());
str.Printf(wxT("%1.*lG"), n_sig1, floor(xmax / dx) * dx + label_dx);
maxwidth = MAX(maxwidth, h / 2 * str.Len());
/* increasing label_dx, if labels would overlap */
while (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
label_base++;
label_dx = pow(10, int_dx) * base[label_base];
if (label_base % 3 == 2 && major_base % 3 == 1) {
major_base++;
major_dx = pow(10, int_dx) * base[major_base];
}
}
x_act = floor(xmin / dx) * dx;
dc.DrawLine(x1, y1, x1 + width, y1);
do {
x_screen = (x_act - xmin) / (xmax - xmin) * width + x1;
xs = (int) (x_screen + 0.5);
if (x_screen > x1 + width + 0.001)
break;
if (x_screen >= x1) {
if (fabs(floor(x_act / major_dx + 0.5) - x_act / major_dx) <
dx / major_dx / 10.0) {
if (fabs(floor(x_act / label_dx + 0.5) - x_act / label_dx) <
dx / label_dx / 10.0) {
/* label tick mark */
dc.DrawLine(xs, y1, xs, y1 + text);
/* grid line */
if (grid != 0 && xs > x1 && xs < x1 + width)
dc.DrawLine(xs, y1, xs, y1 + grid);
/* label */
if (label != 0) {
str.Printf(wxT("%1.*lG"), n_sig1, x_act);
dc.GetTextExtent(str, &w, &h);
dc.DrawText(str, (int) xs - w / 2, y1 + label);
}
} else {
/* major tick mark */
dc.DrawLine(xs, y1, xs, y1 + major);
/* grid line */
if (grid != 0 && xs > x1 && xs < x1 + width)
dc.DrawLine(xs, y1 - 1, xs, y1 + grid);
}
} else
/* minor tick mark */
dc.DrawLine(xs, y1, xs, y1 + minor);
}
x_act += dx;
/* supress 1.23E-17 ... */
if (fabs(x_act) < dx / 100)
x_act = 0;
} while (1);
}
/*------------------------------------------------------------------*/
void DOScreen::DrawTcalib(wxDC& dc, wxCoord width, wxCoord height, bool printing)
{
int x, y, x_old, y_old;
double tscale;
wxString str;
m_dc = &dc;
m_x1[m_board] = 20;
m_y1[m_board] = 1;
m_x2[m_board] = width-1;
m_y2[m_board] = height-20;
x_old = y_old = 0;
tscale = 20/m_osci->GetCurrentBoard()->GetNominalFrequency();
// draw overall frame
if (printing) {
dc.SetBackground(*wxWHITE_BRUSH);
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
} else {
dc.SetBackground(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(*wxBLACK_BRUSH);
}
dc.DrawRectangle(0, 0, width, height);
dc.SetPen(*wxGREY_PEN);
dc.DrawRectangle(m_x1[m_board], m_y1[m_board], m_x2[m_board]-m_x1[m_board], m_y2[m_board]-m_y1[m_board]);
// draw grid
if (m_displayShowGrid) {
dc.SetPen(*wxGREY_PEN);
for (int i=1 ; i<10 ; i++) {
if (i == 5) {
for (int j=m_x1[m_board]+1 ; j<m_x2[m_board] ; j+=2)
DrawDot(dc, j, i*(m_y2[m_board]-m_y1[m_board])/10+m_y1[m_board], printing);
} else {
for (int j=1 ; j<50 ; j++)
DrawDot(dc, m_x1[m_board]+j*(m_x2[m_board]-m_x1[m_board])/50, i*(m_y2[m_board]-m_y1[m_board])/10+m_y1[m_board], printing);
}
}
for (int i=1 ; i<50 ; i++) {
for (int j=-4 ; j<5 ; j+=2)
DrawDot(dc, m_x1[m_board]+i*(m_x2[m_board]-m_x1[m_board])/50, (m_y2[m_board]-m_y1[m_board])/2+m_y1[m_board]+j, printing);
}
for (int i=1 ; i<10 ; i++) {
if (i == 5) {
for (int j=m_y1[m_board]+1 ; j<m_y2[m_board] ; j+=2)
DrawDot(dc, i*(m_x2[m_board]-m_x1[m_board])/10+m_x1[m_board], j, printing);
} else {
for (int j=1 ; j<50 ; j++)
DrawDot(dc, i*(m_x2[m_board]-m_x1[m_board])/10+m_x1[m_board], m_y1[m_board]+j*(m_y2[m_board]-m_y1[m_board])/50, printing);
}
}
for (int i=1 ; i<50 ; i++) {
for (int j=-4 ; j<5 ; j+=2)
DrawDot(dc, (m_x2[m_board]-m_x1[m_board])/2+m_x1[m_board]+j, m_y1[m_board]+i*(m_y2[m_board]-m_y1[m_board])/50, printing);
}
dc.SetFont(m_fontFixedBold);
dc.SetTextForeground(*wxWHITE);
dc.DrawText(wxT("ns"), m_x1[m_board] - 15, m_y1[m_board] + 10);
for (int i=(int)(-tscale*5) ; i<=tscale*5 ; i++) {
int w, h;
str.Printf(wxT("%1.1lf"), -i*tscale/10.0);
dc.GetTextExtent(str, &w, &h);
dc.DrawText(str, m_x1[m_board] - 2 - w, m_y1[m_board]+(5+i)*(m_y2[m_board]-m_y1[m_board])/10 - h/2);
}
}
// draw progress bar
dc.SetBrush(*wxGREEN);
dc.SetPen(*wxWHITE_PEN);
dc.DrawRoundedRectangle(m_x1[m_board], m_y2[m_board]+3, (int)((m_x2[m_board]-m_x1[m_board])*m_frame->GetProgress()/100.0), 6, 2);
// draw waveform in background
dc.SetClippingRegion(m_x1[m_board]+1, m_y1[m_board]+1, m_x2[m_board]-m_x1[m_board]-2, m_y2[m_board]-m_y1[m_board]-2);
dc.SetPen(*wxMEDIUM_GREY_PEN);
dc.SetTextForeground(*wxLIGHT_GREY);
if (m_frame->GetProgress() < 100) {
if (m_osci->GetCurrentBoard()->GetBoardType() == 6)
str.Printf(wxT("Calibration waveform chip %d"), m_osci->GetChip()+1);
else
str.Printf(wxT("Calibration waveform"));
dc.DrawText(str, m_x1[m_board] + 10, m_y1[m_board] + 10);
if (m_osci->GetWaveformDepth(3)) {
float wf[2048];
int tc = m_osci->GetCurrentBoard()->GetStopCell(m_osci->GetChip());
if (m_osci->GetCurrentBoard()->GetBoardType() == 9)
m_osci->GetCurrentBoard()->GetWave(m_osci->GetChip(), 0, wf, true, tc, 0, false);
else
m_osci->GetCurrentBoard()->GetWave(m_osci->GetChip(), 8, wf, true, tc, 0, false);
float *time = m_osci->GetTime(0, 3);
for (int i=0 ; i<m_osci->GetWaveformDepth(3) ; i++) {
x = timeToX(time[i]);
y = voltToY(wf[i]);
if (i > 0)
dc.DrawLine(x_old, y_old, x, y);
x_old = x;
y_old = y;
}
}
}
// draw timing calibration array
dc.SetClippingRegion(m_x1[m_board]+1, m_y1[m_board]+1, m_x2[m_board]-m_x1[m_board]-2, m_y2[m_board]-m_y1[m_board]-2);
if (m_osci->GetWaveformDepth(3)) {
float time[2048];
if (m_osci->GetTimeCalibration(0, 0, 0, time, true)) {
/* differential nonlinearity */
dc.SetPen(*wxGREEN_PEN);
dc.SetTextForeground(*wxGREEN);
dc.DrawText(wxT("Effective bin width"), m_x1[m_board] + 10, m_y1[m_board] + 30);
for (int i=1 ; i<m_osci->GetWaveformDepth(3) ; i++) {
x = (int)((double)i/m_osci->GetWaveformDepth(3)*(m_x2[m_board]-m_x1[m_board])+m_x1[m_board] + 0.5);
y = (int) ((m_y1[m_board]+m_y2[m_board])/2-time[i]/tscale*(m_y2[m_board]-m_y1[m_board]) + 0.5);
if (i > 1)
dc.DrawLine(x_old, y_old, x, y);
x_old = x;
y_old = y;
}
/* integral nonlinearity */
dc.SetPen(*wxRED_PEN);
dc.SetTextForeground(*wxRED);
dc.DrawText(wxT("Integral nonlinearity"), m_x1[m_board] + 10, m_y1[m_board] + 50);
m_osci->GetTimeCalibration(0, 0, 1, time, true);
for (int i=0 ; i<m_osci->GetWaveformDepth(3) ; i++) {
x = (int)((double)i/m_osci->GetWaveformDepth(3)*(m_x2[m_board]-m_x1[m_board])+m_x1[m_board] + 0.5);
y = (int) ((m_y1[m_board]+m_y2[m_board])/2-time[i]/tscale*(m_y2[m_board]-m_y1[m_board]) + 0.5);
if (i > 0)
dc.DrawLine(x_old, y_old, x, y);
x_old = x;
y_old = y;
}
}
}
dc.DestroyClippingRegion();
}
/*------------------------------------------------------------------*/
void DOScreen::DrawMath(wxDC& dc, wxCoord width, wxCoord height, bool printing)
{
for (int math=0 ; math < 2 ; math++)
for (int idx=3 ; idx>=0 ; idx--)
if (m_mathFlag[math][idx]) {
if (math == 0)
DrawPeriodJitter(dc, idx, printing);
}
}
/*------------------------------------------------------------------*/
void DOScreen::DrawPeriodJitter(wxDC& dc, int idx, bool printing)
{
int i, j, w, h, n_pos, n_neg, xs, ys, x_old, y_old;
double miny, maxy, mean;
double t_pos[1000], t_neg[1000], t_average[1000], t_delta[1000];
wxString str;
dc.SetFont(m_fontFixed);
dc.SetClippingRegion(m_x1[m_board]+1, m_y1[m_board]+1, m_x2[m_board]-m_x1[m_board]-2, m_y2[m_board]-m_y1[m_board]-2);
dc.SetPen(wxPen(m_frame->GetColor(idx, printing), 1, wxSOLID));
float *y = m_frame->GetWaveform(0, idx);
float *x = m_frame->GetTime(0, idx);
int n = m_osci->GetWaveformDepth(idx);
miny = maxy = y[0];
for (i=0 ; i<n ; i++) {
if (y[i] > maxy)
maxy = y[i];
if (y[i] < miny)
miny = y[i];
}
mean = (miny + maxy)/2;
if (maxy - miny < 50)
return;
/* search zero crossings */
n_pos = n_neg = 0;
for (i=1 ; i<n ; i++) {
if (y[i] > mean && y[i-1] <= mean) {
t_pos[n_pos++] = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]);
}
if (y[i] < mean && y[i-1] >= mean && n_pos > 0) {
t_neg[n_neg++] = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]);
}
}
if (n_pos == 0 || n_neg == 0)
return;
for (n=i=j=0 ; ; i++,j++) {
if (i+1 >= n_pos)
break;
t_average[n] = (t_pos[i+1] + t_pos[i]) / 2;
t_delta[n++] = t_pos[i+1] - t_pos[i];
if (j+1 >= n_neg)
break;
t_average[n] = (t_neg[j+1] + t_neg[j]) / 2;
t_delta[n++] = t_neg[j+1] - t_neg[j];
}
for (i=0,mean=0 ; i<n ; i++)
mean += t_delta[i];
mean /= n;
x_old = y_old = 0;
for (i=0 ; i<n ; i++) {
xs = timeToX(t_average[i]);
ys = (int) ((m_y1[m_board]+m_y2[m_board])/2-100*(t_delta[i] - mean)/10.0*(m_y2[m_board]-m_y1[m_board]) + 0.5);
if (i > 0)
dc.DrawLine(x_old, y_old, xs, ys);
x_old = xs;
y_old = ys;
}
str.Printf(wxT("%1.3lf ns"), mean);
dc.SetPen(wxPen(*wxLIGHT_GREY, 1, wxSOLID));
dc.SetTextForeground(*wxGREEN);
dc.SetBrush(*wxBLACK);
dc.GetTextExtent(str, &w, &h);
dc.DrawRoundedRectangle(m_x1[m_board]+1, m_y1[m_board]+(m_y2[m_board]-m_y1[m_board])/2 - h/2, w+5, h, 2);
dc.DrawText(str, m_x1[m_board] + 3, m_y1[m_board]+(m_y2[m_board]-m_y1[m_board])/2 - h/2);
str.Printf(wxT("+10 ps"));
dc.GetTextExtent(str, &w, &h);
dc.DrawRoundedRectangle(m_x1[m_board]+1, m_y1[m_board]+4*(m_y2[m_board]-m_y1[m_board])/10 - h/2, w+5, h, 2);
dc.DrawText(str, m_x1[m_board]+3, m_y1[m_board]+4*(m_y2[m_board]-m_y1[m_board])/10 - h/2);
str.Printf(wxT("-10 ps"));
dc.GetTextExtent(str, &w, &h);
dc.DrawRoundedRectangle(m_x1[m_board]+1, m_y1[m_board]+6*(m_y2[m_board]-m_y1[m_board])/10 - h/2, w+5, h, 2);
dc.DrawText(str, m_x1[m_board]+3, m_y1[m_board]+6*(m_y2[m_board]-m_y1[m_board])/10 - h/2);
}
/*------------------------------------------------------------------*/
void DOScreen::OnSize(wxSizeEvent& event)
{
wxWindow::Refresh();
}
/*------------------------------------------------------------------*/
void DOScreen::SetScale(int b, int idx, int scale)
{
m_scale[b][idx] = scale;
}
/*------------------------------------------------------------------*/
void DOScreen::SetHScale(int b, int hscale)
{
m_hscale[b] = hscale;
m_screenSize[b] = m_hscaleTable[hscale] * 10;
}
/*------------------------------------------------------------------*/
void DOScreen::SetHScaleInc(int b, int increment)
{
int s = m_hscale[b] += increment;
if (s < 0)
s = 0;
/* limit to min 500 ns/div */
if (s > 8)
s = 8;
SetHScale(b, s);
}
/*------------------------------------------------------------------*/
void DOScreen::OnMouse(wxMouseEvent& event)
{
wxSize s;
int x, y, i, b;
if (m_clientHeight > 21 && m_clientWidth > 21) {
m_mouseX = (double) (event.GetPosition().x - m_x1[m_frame->GetCurrentBoard()]) /
(m_x2[m_frame->GetCurrentBoard()] - m_x1[m_frame->GetCurrentBoard()]);
m_mouseY = (double) (event.GetPosition().y - m_y1[m_frame->GetCurrentBoard()]) /
(m_y2[m_frame->GetCurrentBoard()] - m_y1[m_frame->GetCurrentBoard()]);
}
bool hand = false;
bool sizewe = false;
x = event.GetPosition().x;
y = event.GetPosition().y;
if (x > m_MeasX1 && x < m_MeasX2 &&
y > m_MeasY1 && y < m_MeasY2) {
hand = true;
if (event.LeftDown())
m_frame->StatReset();
}
for (int i=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
if (x > m_BSX1[i] && x < m_BSX2[i] &&
y > m_BSY1[i] && y < m_BSY2[i]) {
hand = true;
if (event.LeftDown()) {
m_splitMode = false;
m_frame->SetSplitMode(false);
m_frame->SelectBoard(i); // select different board
m_frame->SetCursorA(false);
m_frame->SetCursorB(false);
}
break;
}
}
if (m_osci->IsMultiBoard()) {
int i = m_osci->GetNumberOfBoards();
if (x > m_BSX1[i] && x < m_BSX2[i] &&
y > m_BSY1[i] && y < m_BSY2[i]) {
hand = true;
if (event.LeftDown()) {
m_splitMode = true;
m_frame->SetSplitMode(true);
m_frame->SetCursorA(false);
m_frame->SetCursorB(false);
}
}
}
int tip = 0;
if (m_frame->IsHist()) {
// save button
if (x > m_savex1 && x < m_savex2 && y > m_savey1 && y < m_savey2) {
tip = 4;
if (event.LeftDown())
m_frame->SaveHisto();
}
// left handle
if (x > m_hx1 && x < m_hx1+15 && y > (m_hy1+m_hy2)/2-10 && y < (m_hy1+m_hy2)/2+10) {
hand = true;
tip = 1;
if (event.LeftDown()) {
m_minCursor = m_histAxisMin;
m_histAxisAuto = false;
m_dragMin = true;
}
}
// right handle
if (x > m_hx2-15 && x < m_hx2 && y > (m_hy1+m_hy2)/2-10 && y < (m_hy1+m_hy2)/2+10) {
hand = true;
tip = 2;
if (event.LeftDown()) {
m_maxCursor = m_histAxisMax;
m_histAxisAuto = false;
m_dragMax = true;
}
}
// auto scale button
if (!m_histAxisAuto && x > (m_hx1+m_hx2)/2-15 && x < (m_hx1+m_hx2)/2+15 &&
y > m_hy2-10 && y < m_hy2+4) {
hand = true;
tip = 3;
if (event.LeftDown()) {
m_histAxisAuto = true;
}
}
if (event.Dragging() && m_dragMin) {
m_minCursor = m_histAxisMin + (m_histAxisMax - m_histAxisMin) * (x - m_hx1)/(m_hx2 - m_hx1);
sizewe = true;
}
if (event.LeftUp() && m_dragMin) {
m_histAxisMin = m_minCursor;
m_dragMin = false;
}
if (event.Dragging() && m_dragMax) {
m_maxCursor = m_histAxisMin + (m_histAxisMax - m_histAxisMin) * (x - m_hx1)/(m_hx2 - m_hx1);
sizewe = true;
}
if (event.LeftUp() && m_dragMax) {
m_histAxisMax = m_maxCursor;
m_dragMax = false;
}
}
if (tip == 1)
this->SetToolTip(wxT("Drag right to set minimum"));
else if (tip == 2)
this->SetToolTip(wxT("Drag left to set maximum"));
else if (tip == 3)
this->SetToolTip(wxT("Auto zoom to show all values"));
else if (tip == 4)
this->SetToolTip(wxT("Save histogram"));
else
this->SetToolTip(NULL);
if (sizewe)
SetCursor(wxCURSOR_SIZEWE);
else if (hand)
SetCursor(wxCURSOR_HAND);
else
SetCursor(wxNullCursor);
if (event.LeftDown()) {
this->SetFocus();
if (m_splitMode) {
for (i=b=0 ; i<m_osci->GetNumberOfBoards() ; i++) {
if (x > m_x1[i] && x < m_x2[i] &&
y > m_y1[i] && y < m_y2[i]) {
b = i;
break;
}
}
if (b != m_frame->GetCurrentBoard()) {
m_frame->SelectBoard(b);
}
}
if (x > m_x1[m_frame->GetCurrentBoard()] && x < m_x2[m_frame->GetCurrentBoard()] &&
y > m_y1[m_frame->GetCurrentBoard()] && y < m_y2[m_frame->GetCurrentBoard()]) {
if (m_frame->ActiveCursor() == 1)
m_frame->SetActiveCursor(0);
else if (m_frame->ActiveCursor() == 2)
m_frame->SetActiveCursor(0);
else {
if (m_frame->IsCursorA() && !m_frame->IsCursorB())
m_frame->SetActiveCursor(1);
else if (!m_frame->IsCursorA() && m_frame->IsCursorB())
m_frame->SetActiveCursor(2);
else if (m_frame->IsCursorA() && m_frame->IsCursorB()){
// activate cursor close to mouse pointer
double d1 = (m_xCursorA-m_mouseX)*(m_xCursorA-m_mouseX) +
(m_yCursorA-m_mouseY)*(m_yCursorA-m_mouseY);
double d2 = (m_xCursorB-m_mouseX)*(m_xCursorB-m_mouseX) +
(m_yCursorB-m_mouseY)*(m_yCursorB-m_mouseY);
m_frame->SetActiveCursor(d1 < d2 ? 1 : 2);
}
}
}
}
if (event.RightDown()) {
m_frame->ToggleControls();
}
wxWindow::Refresh();
}