📄 waveformdisplay.cpp
字号:
// WaveformDisplay.cpp : implementation file
//
#include "stdafx.h"
#define PACKED
#pragma pack(1)
#include "usb_protocol.h"
#pragma pack()
#include "scope_control.h"
#include "lmscope.h"
#include "WaveformDisplay.h"
#include "lmscopeDlg.h"
//***************************************************************************
//
// Macro converting from a millivolt measurement to a Y pixel coordinate
// given a voltage scaling factor.
//
//***************************************************************************
#define MV_TO_Y(mv, scale) (m_iGraticuleOriginY - \
(((mv) * m_iGraticuleSide) / (long)(scale)))
const COLORREF g_colWaveformColors[NUM_WAVEFORM_COLORS] =
{
SCOPE_COLOR_BACKGROUND,
SCOPE_COLOR_CHANNEL_1,
SCOPE_COLOR_CHANNEL_2,
SCOPE_COLOR_GRATICULE,
SCOPE_COLOR_TRIG_POS,
SCOPE_COLOR_TRIG_LEVEL
};
//***************************************************************************
//
// CWaveformDisplay class
//
//***************************************************************************
IMPLEMENT_DYNAMIC(CWaveformDisplay, CStatic)
CWaveformDisplay::~CWaveformDisplay()
{
}
void CWaveformDisplay::DoDataExchange(CDataExchange* pDX)
{
CStatic::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CWaveformDisplay, CStatic)
END_MESSAGE_MAP()
//***************************************************************************
//
// CWaveform member functions.
//
//***************************************************************************
CWaveformDisplay::CWaveformDisplay() : CStatic()
{
//
// Set defaults for the waveform elements we will draw.
//
m_bShowGraticule = TRUE;
m_bShowTrigLevel = TRUE;
m_bShowTrigPos = TRUE;
//
// Set defaults for various fields we expect the client to set
// later.
//
m_pScopeData = NULL;
m_pSingleElement = NULL;
m_pDualElement = NULL;
m_iTriggerPos = 0;
m_lTriggerLevelmV = 0;
m_uluSPerDivision = 100;
m_lVerticalOffsetmV[0] = 0;
m_lVerticalOffsetmV[1] = 0;
m_ulmVPerDivision[0] = 500;
m_ulmVPerDivision[1] = 500;
}
//***************************************************************************
//
// Initialize the bitmap we use for offscreen drawing.
//
//***************************************************************************
void CWaveformDisplay::InitBitmap(void)
{
CBitmap * pOldBitmap;
CDC *pDC;
CDC MemDC;
CRect rectArea;
//
// Determine the size of the area we are going to be rendering into.
//
GetClientRect(&rectArea);
m_sizeWaveform = rectArea.Size();
m_iGraticuleSide = m_sizeWaveform.cx / NUM_HORIZONTAL_DIVISIONS;
m_iGraticuleOriginY = (((m_sizeWaveform.cy / m_iGraticuleSide) / 2) *
m_iGraticuleSide);
// Need a DC
pDC = GetDC();
// And a memory DC, set Map Mode
MemDC.CreateCompatibleDC(pDC);
// Create a bitmap big enough to hold the window's image
m_bmpWaveform.CreateCompatibleBitmap(pDC, m_sizeWaveform.cx, m_sizeWaveform.cy);
// Select the bitmap into the memory DC
pOldBitmap = MemDC.SelectObject(&m_bmpWaveform);
// Draw the initial waveform display (background and graticule only)
DrawWaveform(&MemDC);
// Select the original bitmap back in
MemDC.SelectObject(pOldBitmap);
// Clean up
ReleaseDC(pDC);
//
// Associate the static picture control with our offscreen bitmap
//
SetBitmap((HBITMAP)m_bmpWaveform);
}
//***************************************************************************
//
// This function is called whenever new data is received from the
// oscilloscope. It renders the data into our offscreen bitmap then causes
// the picture control on the dialog box to be refreshed.
//
//***************************************************************************
void CWaveformDisplay::RenderWaveform(tScopeDataStart *pScopeData,
int iElementOffset)
{
//
// If we already have a dataset, discard it.
//
if(m_pScopeData)
{
LocalFree(m_pScopeData);
}
//
// Hold on to the new dataset.
//
m_pScopeData = pScopeData;
//
// Calculate pointers to the first data element in the dataset.
// Even though the dataset can only be either single or dual
// channel, we keep two pointers anyway.
//
m_pDualElement = (tScopeDualDataElement *)((char *)pScopeData +
iElementOffset);
m_pSingleElement = (tScopeDataElement *)((char *)pScopeData +
iElementOffset);
//
// Call our internal function to render the new data.
//
InternalRenderWaveform();
}
//***************************************************************************
//
// This internal function is called to redraw the existing waveform dataset
// after a display parameter change or when new data has just been sent by
// the client.
//
//***************************************************************************
void CWaveformDisplay::InternalRenderWaveform(void)
{
CBitmap * pOldBitmap;
CDC *pDC;
CDC MemDC;
CRect rectArea;
//
// Get a device context.
//
pDC = GetDC();
//
// Create a memory DC compatible with the one we just got.
//
MemDC.CreateCompatibleDC(pDC);
//
// Select the bitmap into the memory DC
//
pOldBitmap = MemDC.SelectObject(&m_bmpWaveform);
//
// Draw the waveform display
//
DrawWaveform(&MemDC);
//
// Select the original bitmap back in.
//
MemDC.SelectObject(pOldBitmap);
//
// Clean up
//
ReleaseDC(pDC);
//
// Invalidate the rectangle associated with the waveform picture control.
//
Invalidate(FALSE);
}
//***************************************************************************
//
// Render the latest waveform data, if any, into our offscreen bitmap.
//
//***************************************************************************
void CWaveformDisplay::DrawWaveform(CDC *pDC)
{
long lCenterOffset;
long lY;
long lX;
COLORREF dwColor = SCOPE_COLOR_BACKGROUND;
CPen cPenTrigPos(PS_SOLID, 1, SCOPE_COLOR_TRIG_POS);
CPen cPenTrigLevel(PS_SOLID, 1, SCOPE_COLOR_TRIG_LEVEL);
CPen *pOldPen;
//
// Fill the background of the bitmap with grey.
//
pDC->FillSolidRect(0, 0, m_sizeWaveform.cx, m_sizeWaveform.cy, dwColor);
//
// Draw the graticule if required.
//
if(m_bShowGraticule)
{
DrawGraticule(pDC);
}
//
// Render the actual waveform itself.
//
if(m_pScopeData)
{
//
// Determine the horizontal offset to apply to the waveform to ensure
// that the trigger position is where we expect it to be (centered by
// default).
//
lCenterOffset = GetCenterOffset();
//
// Draw a vertical line at the trigger point.
//
if(m_bShowTrigPos)
{
//
// Select our pen into the DC.
//
pOldPen = pDC->SelectObject(&cPenTrigPos);
//
// Determine where on the display the trigger point falls
//
lY = m_pScopeData->ulTriggerIndex;
//
// Now determine where we need to draw the trigger position line.
//
lX = SampleIndexToX(lY, CHANNEL_1);
//
// If the trigger position is visible in the waveform area of the
// screen, draw a vertical line there.
//
if((lX >= 0) && (lX < m_sizeWaveform.cx))
{
pDC->SetDCPenColor(SCOPE_COLOR_TRIG_POS);
pDC->MoveTo(lX, 0);
pDC->LineTo(lX, m_sizeWaveform.cy);
}
//
// Revert to the previous pen.
//
pDC->SelectObject(pOldPen);
}
//
// ...and a horizontal line at the trigger level.
//
if(m_bShowTrigLevel)
{
//
// Convert the trigger level into a Y pixel offset.
//
lY = SampleToY((short)m_lTriggerLevelmV, (m_pScopeData->bCh2SampleFirst ?
CHANNEL_2 : CHANNEL_1));
if((lY >= 0) && (lY <= m_sizeWaveform.cy))
{
//
// Select our pen into the DC.
//
pOldPen = pDC->SelectObject(&cPenTrigLevel);
//
// Draw the line
//
pDC->MoveTo(0, lY);
pDC->LineTo(m_sizeWaveform.cx, lY);
//
// Revert to the previous pen
//
pDC->SelectObject(pOldPen);
}
}
//
// Render the waveform for channel 1
//
DrawSingleWaveform(pDC, CHANNEL_1, SCOPE_COLOR_CHANNEL_1);
//
// Yes - render the waveform for channel 2
//
DrawSingleWaveform(pDC, CHANNEL_2, SCOPE_COLOR_CHANNEL_2);
}
}
//***************************************************************************
//
// Draw the graticule lines on our offscreen bitmap.
//
//***************************************************************************
void CWaveformDisplay::DrawGraticule(CDC *pDC)
{
int iX;
int iY;
CPen cPen(PS_SOLID, 1, SCOPE_COLOR_GRATICULE);
CPen *pcPenOld;
//
// Set the pen color for the graticule lines.
//
pcPenOld = pDC->SelectObject(&cPen);
//
// Draw the vertical lines.
//
for(iX = m_iGraticuleSide; iX < m_sizeWaveform.cx; iX += m_iGraticuleSide)
{
pDC->MoveTo(iX, 0);
pDC->LineTo(iX, m_sizeWaveform.cy);
}
//
// Draw the horizontal lines.
//
for(iY = m_iGraticuleSide; iY < m_sizeWaveform.cy; iY += m_iGraticuleSide)
{
pDC->MoveTo(0, iY);
pDC->LineTo(m_sizeWaveform.cx, iY);
}
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -