Follow us on Facebook
Follow us on Twitter
Signalogic on LinkedIn

Digital Oscilloscope C/C++ Source Code Example of Using DirectDSP® software

Source Code Home

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 

    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);

 // 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);


    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



        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);
                  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);


            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);



    return 0L;