Digital Oscilloscope C/C++ Source Code Example of Using DirectDSP? software
Below is a C/C++ source code example of using off-the-shelf DSP/analog hardware to perform a basic digital oscilloscope function. Note the use of the DSShowHardwareSelector call to bring up a list of supported hardware.
#include <windows.h>
#include <stdlib.h>
// DirectDSP? software package include files
#include "enmgr.h" // Engine Manager
#include "hwmgr.h" // Hardware Manager
#include "hwlib.h" // Hardware Library
// some global variables
...note: many variable and type declarations omitted for brevity...
HANDLE FAR hEngine = NULL; // declare at least one variable FAR to limit this to a
single-instance program
HANDLE hBoard = NULL;
BOOL fBoardInitialized = FALSE;
char szBoard[30];
UINT uMemArch;
int wBuflen = 1024;
DWORD dwMemSize,dwBufferBaseAddr;
HWND hwndScope = NULL;
WORD wBoardClass;
float FsDesired = 22050.0;
float FsActual;
DWORD dwFsMode;
short int ChanList = 0;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInst, LPSTR lpszCmdParam, int nCmdShow) {
// comment this call if status messages from HwLib should not be visible
DSShowEngMgrStatusWindow(); // turn on debug status window in Engine Manager
// show hardware selector dialog (Hardware Manager); returns board designator string
// note: if hardware choice is fixed, then skip this call and use correct board
designator string
// in DSAssignBoard call below
if (DSShowHardwareSelectorDlg(NULL, szBoard) == IDCANCEL) goto cleanup;
// open engine
hEngine = DSEngineOpen(DS_EO_HSM, NULL); // first try to open Hypersignal-Macro or
// Hypersignal-Macro EX as engine
if (!hEngine) {
hEngine = DSEngineOpen(DS_EO_HSA, NULL); // if that doesn't work, try
// Hypersignal-Acoustic
if (!hEngine) {
itoa(DSGetHWLibErrorStatus(), tmpstr, 10);
lstrcat(tmpstr, " is error code; DSEngineOpen failed");
MessageBox(GetActiveWindow(), tmpstr, "Dscope Test Prog", MB_OK);
goto cleanup;
}
}
// assign a board handle: engine handle, board designator, bus type, IO base addr,
Mem base addr
hBoard = DSAssignBoard(hEngine, szBoard, NULL, NULL, NULL);
// initialize the board; make sure it's installed, reset all processors
fBoardInitialized = DSInitBoard(hBoard);
if (!fBoardInitialized) {
itoa(DSGetEngineErrorStatus(hEngine), tmpstr, 10);
lstrcat(tmpstr, " is error code; DSInitBoard failed");
MessageBox(GetActiveWindow(), tmpstr, "Dscope Test Prog", MB_OK);
goto cleanup;
}
// interrogate engine for board type values
wBoardClass = DSGetBoardClass(hBoard);
// get memory architecture
uMemArch = DSGetMemArch(hBoard);
if (uMemArch == NULL) {
MessageBox(GetActiveWindow(), "DSGetMemArch failed","Dscope Test Prog", MB_OK);
goto cleanup;
}
// determine sampling rate ctrl. reg. value, and actual rate (closest rate possible
to desired);
// CalcSampFreq returns ctrl. reg. value directly, uses ptr to return actual
sampling frequency (in Hz)
dwFsMode = DSCalcSampFreq(hBoard, FsDesired, 1, &ChanList, &FsActual); // demo
assumes 1 channel, initial value 22.05 kHz
// load executable DSP code file (usually a COFF file produced by DSP manufacturer's
linker)
if (!DSLoadFileProcessor(hBoard, NULL, 1)) { // load default file for the board
type (processor 0 only)
MessageBox(GetActiveWindow(), "DSLoadFileBoard: problem loading file", "Dscope
Test Prog", MB_OK);
goto cleanup;
}
// get the memory size, (note that this currently has to be done after LoadFile)
dwMemSize = DSGetMemSize(hBoard, 0x01); // processor 0 only
// reset the DSP board (should already be in reset state; processor 0 only)
DSResetProcessor(hBoard, 0x01);
// send down some important variables (needed if a default Hypersignal DSP file is
being used)
DSPutDSPProperty(hBoard, DSP_BOARDCLASS, wBoardClass & 0x0ff); // main type in
low byte
DSPutDSPProperty(hBoard, DSP_BOARDSUBCLASS, wBoardClass >> 8); // subtype in
high byte
DSPutDSPProperty(hBoard, DSP_OPMODE, 2); // Dig. Scope is mode 2
DSPutDSPProperty(hBoard, DSP_FILTTYPE1, 0); // disable trace 1 real-time filter
DSPutDSPProperty(hBoard, DSP_FILTTYPE2, 0); // disable trace 2 real-time filter
DSPutDSPProperty(hBoard, DSP_TRIGLEVEL, 0); // free-run triggering
DSPutDSPProperty(hBoard, DSP_TRIGCHANLIST, 0);
DSPutDSPProperty(hBoard, DSP_BUFLEN, wBuflen); // buffer size
DSPutDSPProperty(hBoard, DSP_HOSTBUFNUM, 0);
DSPutDSPProperty(hBoard, DSP_BUFNUM, 0);
DSPutDSPProperty(hBoard, DSP_CHANLIST, 0); // starting channel
DSPutDSPProperty(hBoard, DSP_NUMCHAN, 1); // number of channels
DSPutDSPProperty(hBoard, DSP_GAINLIST, 0); // gain list
DSPutDSPProperty(hBoard, DSP_FSMODE, dwFsMode); // sampling rate control register
(mode value)
DSPutDSPProperty(hBoard, DSP_FSVALUE, *((long*)&FsActual)); // actual sampling rate
(in Hz)
// get address of input time domain data
dwBufferBaseAddr = DSGetDSPProperty(hBoard, DSP_TIMDATAADDR);
if (!hPrevInst) {
...note: window class registration and CreateWindow code omitted for brevity...
hwndScope = CreateWindow(...
ShowWindow(hwndScope, nCmdShow);
UpdateWindow(hwndScope);
}
// scope window is born; turn the board loose... (processor 0 only)
DSRunProcessor(hBoard, 0x01);
// tell engine to wait for a buffer, and then send a BUFRDY message to our window when
one is ready
DSRegisterEngineMsgWnd(hEngine, DS_REMW_SETDSPDATARDYMSG, hwndScope); // register
callback window for buffer ready messages
DSWaitForBuffer(hBoard, 0, NULL, DS_WFB_POLLED);
// time to give up and become a Windows animal
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
cleanup:
if (fBoardInitialized) DSDisableBoard(hBoard); // disable board (all processors)
if (hBoard != NULL) DSFreeBoard(hBoard);
if (hEngine != NULL) DSEngineClose(hEngine);
return msg.wParam;
}
long WINAPI _export WndProc(HWND hwnd, WORD wMsg, WORD wParam, LONG lParam) {
...note: most variable declarations omitted for brevity...
static HGLOBAL hBuf = NULL;
static int far* buf;
static short int nCurBuf = 0;
switch (wMsg) {
...note: other message-processing code omitted for brevity...
case WM_CREATE:
// allocate some memory to hold board buffers
hBuf = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DISCARDABLE,
MAX_BUF_LEN*sizeof(int));
break;
case WM_DSPENGINE_BUFRDY: // message sent by DSP engine when data buffer is ready
buf = (int far*)GlobalLock(hBuf);
// transfer below illustrates two common type of DSP memory architectures
if (uMemArch == DS_GMA_VECTOR) { // vector data memory
if (nCurBuf == 0)
uStatus = DSGetMem(hBoard, DS_GM_VECTOR_DATA_X, dwBufferBaseAddr,
DS_GM_SIZE16, buf, wBuflen);
else
uStatus = DSGetMem(hBoard, DS_GM_VECTOR_DATA_Y, dwBufferBaseAddr,
DS_GM_SIZE16, buf, wBuflen);
}
else { // linear data/prog memory, or modified harvard arch. with linear
data memory
uStatus = DSGetMem(hBoard, DS_GM_LINEAR_DATA_RT,
dwBufferBaseAddr+nCurBuf*wBuflen, DS_GM_SIZE16, buf, wBuflen);
}
GlobalUnlock(hBuf);
if (!uStatus) MessageBox(hwnd, "DSGetMem: problem with point transfer",
"Dscope Test Prog", MB_OK);
else FirstBufferRcvd = TRUE;
nCurBuf ^= 1; // switch buffers
DSPutDSPProperty(hBoard, DSP_HOSTBUFNUM, nCurBuf); // write the new buffer #
if (!IsIconic(hwnd)) DSWaitForBuffer(hBoard, nCurBuf, NULL, DS_WFB_POLLED);
break;
}
return 0L;
} |