Signalogic Logo.

DSP Hardware, DSP Software

C54xx C67xx DSP

MATLAB DSP, media gateway DSP, wireless DSP, PC/104 DSP

Strip Chart Recorder C/C++ Source Code Example

Strip Chart Recorder C/C++ Source Code Example of Using DSPower®-HwLib or DirectDSP™ software

Below is a C/C++ source code example of using off-the-shelf DSP/analog hardware to perform a basic strip chart recorder function. Note the use of the DSShowHardwareSelector call to bring up a list of supported hardware.

#include <windows.h>
#include <stdlib.h>


// DSPower®-HwLib or 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;
WORD        wBoardClass;
DWORD       dwMemSize,dwBufferBaseAddr;

HWND        hwndStrip = NULL;

float       FsActual = 8000.0;
DWORD       dwFsMode;

short int   NumChan = 1;
short int   ChanList[MAXCHAN] = { 0, 0, 0, 0, 0, 0, 0, 0 };

DWORD       dwBuflen = 4096;  // default buffer size is small to accommodate 
EVM/eval type boards
DWORD       dwNumAcquired = 0L;
DWORD       dwNumRequested = 40000L;

BOOL        fRunning = FALSE;

char        pathstrWvfrm[144] = "test";


int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInst, LPSTR lpszCmdParam, int 
nCmdShow) {

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

 // comment this call if status messages from HwLib should not be visible

    DSShowEngMgrStatusWindow();  // turn on debug status window in Engine Manager

 // create window for signal display, to hold toolbars, and to receive BUFRDY 
 //and other messages from engine

    if (!hPrevInst) {

  ...note:  window class registration and CreateWindow code omitted 
for brevity...
  
        hwndStrip = CreateWindow(...

        ShowWindow(hwndStrip, nCmdShow);
        UpdateWindow(hwndStrip);
    }


  // 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(NULL, tmpstr, szApp, 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(NULL, tmpstr, szApp, MB_OK);
        goto Cleanup;
    }


 // interrogate engine for board type values

    wBoardClass = DSGetBoardClass(hBoard);


 // get memory architecture

    uMemArch = DSGetMemArch(hBoard);

    if (uMemArch == NULL) {

       MessageBox(NULL,"DSGetMemArch failed", szApp, MB_OK);
       goto Cleanup;
    }


 // 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(NULL, "DSLoadFileBoard:  problem loading file", szApp, 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

 // get address of input time domain data

    dwBufferBaseAddr = DSGetDSPProperty(hBoard, DSP_TIMDATAADDR);

 // reset DSP board (should already be in reset state; processor 0 only)

    DSResetProcessor(hBoard, 0x01);


 // register window to receive BUFRDY messages

    DSRegisterEngineMsgWnd(hEngine, DS_REMW_SETDSPDATARDYMSG, hwndStrip);  
// register callback window for buffer ready messages


 // time to give up and become a Windows animal

    while (GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    hwndStrip = NULL;


Cleanup:

    if (hwndStrip != NULL) DestroyWindow(hwndStrip);

    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 short int  nCurBuf = 0;
static BOOL       FirstBufferRcvd = FALSE;


    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, 
		dwBuflen*sizeof(short));

            break;


        case WM_COMMAND:

            switch (wParam) {

                case DS_ATC_RUNBOARD:

                    if (fRunning) break;  // already running

                 // 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, 0);           
				// acquisition is mode 0

                    if (DSGetBoardInfo(hBoard, DS_GBI_DSPWORDLENGTH) == 24) 
				nShift = 7;  // don't ask; weird efficiency thing required 
				by DSP5600x boards
                    else nShift = 0;

                    DSPutDSPProperty(hBoard, DSP_SCALEIN, 256L << nShift);

                    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, dwBuflen);    
				// buffer size

                    DSPutDSPProperty(hBoard, DSP_HOSTBUFNUM, 0);       
				// starting buffer numbers
                    DSPutDSPProperty(hBoard, DSP_BUFNUM, 0);

                    DSPutDSPProperty(hBoard, DSP_NUMCHAN, NumChan);    
				// number of channels

                    dw = 0;
                    for (j=0; j= 32) {

                        fAmp1 = 0.0;
                        fAmp2 = 0.0;
                        DSIEEEToDSP(hBoard, DS_DTI_IEEESIZE32, &fAmp1, &dw1, 1);
                        DSIEEEToDSP(hBoard, DS_DTI_IEEESIZE32, &fAmp2, &dw2, 1);
                    }
                    else {

                        dw1 = 0;
                        dw2 = 0;
                    }

                    DSPutDSPProperty(hBoard, DSP_MAXVAL1, dw1);          
			// init max. amplitude values maintained by acquisition driver
                    DSPutDSPProperty(hBoard, DSP_MAXVAL2, dw2);

                 // 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, FsActual, NumChan, 
			(short far*)&ChanList, &FsActual);

                    DSPutDSPProperty(hBoard, DSP_FSMODE, dwFsMode);    
			// sampling rate control register (mode value)

                    DSPutDSPProperty(hBoard, DSP_FSVALUE, *((long*)&FsActual));  
			// actual sampling rate (in Hz)

                 // reset counters

                    dwNumAcquired = 0;


                 // reset waveform file

                    p = _fstrchr(pathstrWvfrm, '\\');

                    if (p == NULL) {  // if no user-specified path info...

                        DSGetEngineWaveformPath(hEngine, pathstr);
                        lstrcat(pathstr, "\\");
                        lstrcat(pathstr, pathstrWvfrm);
                    }
                    else lstrcpy(pathstr, pathstrWvfrm);

                    p = _fstrchr(pathstr, '.');
                    if (p == NULL) lstrcat(pathstr, ".tim");

                    hFile = DSOpenFile(pathstr, EXISTS);

                    if (hFile != NULL) {

                        lstrcpy(tmpstr, "Waveform file ");
                        lstrcat(tmpstr, pathstr);
                        lstrcat(tmpstr, " already exists; overwrite?");
                        j = MessageBox(hwnd, tmpstr, szApp, MB_ICONQUESTION | 
				MB_YESNO);

                        if (j == IDNO) {

                            hFile = NULL;
                            break;
                        }
                    } 

                    hFile =  DSOpenFile(pathstr, CREATE);
                    if (hFile == NULL) MessageBox(hwnd, "Waveform file could 
			not be created", szApp, MB_ICONEXCLAMATION);

                 // initialize waveform file header

                    DSInitWvfrmHeader(hFile, HYPLONG);  // Hypersignal format; 
			long header

                    DSSetWvfrmHeader(hFile, DATAPREC, FIXED | 16);
                    DSSetWvfrmHeader(hFile, NUMCHAN, NumChan);
                    DSSetWvfrmHeader(hFile, SAMPFREQ, (long)FsActual);
                    DSSetWvfrmHeader(hFile, EXPONENT, 0);
                    DSSetWvfrmHeader(hFile, FRMLEN, dwBuflen);

                    DSWriteWvfrmHeader(hFile);  // leave file pos at end of header, 
			start of data


                 // run board (processor 0 only)

                    DSRunProcessor(hBoard, 0x01);


                 // initialize wait for buffer

                    DSWaitForBuffer(hBoard, 0, NULL, DS_WFB_POLLED);


                 // update status

                    fRunning = TRUE;

                    SendMessage(hwnd, WM_UPDATESTATUS, 0, 0L);

                    break;


                case DS_ATC_STOPBOARD:

                    if (fRunning) { // not stopped yet?

                        DSResetProcessor(hBoard, 0x01);  // data acquired?  
				stop board

                        fRunning = FALSE;
                    }

                    SendMessage(hwnd, WM_UPDATESTATUS, 0, 0L);  // update status bar

                    if (hFile != NULL) {  // update waveform header with maximum 
			amplitude and length in samples

                     // record max amplitude

                        dw1 = DSGetDSPProperty(hBoard, DSP_MAXVAL1);
                        dw2 = DSGetDSPProperty(hBoard, DSP_MAXVAL2);


                        if (DSGetBoardInfo(hBoard, DS_GBI_DSPWORDLENGTH) >= 32) 
				{  // 32-bit floating-point board?

                            DSDSPToIEEE(hBoard, DS_DTI_IEEESIZE32, &dw1, &fAmp1, 1);
                            DSDSPToIEEE(hBoard, DS_DTI_IEEESIZE32, &dw2, &fAmp2, 1);

                            fAmp = max(fabs(fAmp1), fabs(fAmp2));
                        }
                        else fAmp = max(labs((long)dw1), labs((long)dw2));  
				// 16-bit or 24-bit fixed-point board


                        fAmp = max(min(fAmp, 32767.0), 0.0);

                        DSUpdateHeader(hFile, WVFRMLEN, dwNumAcquired*NumChan);
                        DSUpdateHeader(hFile, MAXAMP, (long)&fAmp);  // default; 
				update at end of run

                        DSCloseFile(hFile);
                        hFile = NULL;
                    }

                    break;

            }

            break;


        case WM_DSPENGINE_BUFRDY:  // message sent by DSP engine when data 
		buffer is ready

         // stop board ASAP if acquired data meets request (especially helpful 
		in cases where very high sampling rate is being used with one 
		large buffer)

            dwNumAcquired += dwBuflen/NumChan;

            if (dwNumAcquired >= dwNumRequested) {

                DSResetProcessor(hBoard, 0x01);  // stop board

                fRunning = FALSE;

                SendMessage(hwnd, WM_UPDATESTATUS, 0, 0L);  // update status
            }


            pBuf = (short 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, pBuf, dwBuflen);
                else
                  uStatus = DSGetMem(hBoard, DS_GM_VECTOR_DATA_Y, dwBufferBaseAddr, 
			DS_GM_SIZE16, pBuf, dwBuflen);
            }
            else { // linear data/prog memory, or modified harvard arch. with 
			linear data memory

                uStatus = DSGetMem(hBoard, DS_GM_LINEAR_DATA_RT, 
		dwBufferBaseAddr+nCurBuf*dwBuflen, DS_GM_SIZE16, pBuf, dwBuflen);
            }

            GlobalUnlock(hBuf);


            if (!uStatus) {

                DSResetProcessor(hBoard, 0x01);  // error; stop board
                MessageBox(hwnd, "DSGetMem:  problem with point transfer", 
			szApp, MB_OK);
                goto Done;
            }

         // allocate temp area for disk write (to tolerate some overflow 
		of messages)

            hBufWr = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, 
		dwBuflen*sizeof(short));

            if (hBufWr != NULL) {

                pBufWr = (short far*)GlobalLock(hBufWr);
                pBuf = (short far*)GlobalLock(hBuf);

                hmemcpy(pBufWr, pBuf, dwBuflen*sizeof(short));

                GlobalUnlock(hBuf);
                GlobalUnlock(hBufWr);
            }


            FirstBufferRcvd = TRUE;  // at least one buffer received

            if (dwNumAcquired < dwNumRequested) {

             // wait for next buffer as long as window is not minimized

                nCurBuf ^= 1;  // switch buffers
                DSPutDSPProperty(hBoard, DSP_HOSTBUFNUM, nCurBuf);  
		// write the new buffer #

                if (!IsIconic(hwnd)) DSWaitForBuffer(hBoard, nCurBuf, 
		NULL, DS_WFB_POLLED);
            }


            if (uStatus) {

             // write new data to waveform file

                if (hBufWr != NULL && hFile != NULL) {

                    pBufWr = (short far*)GlobalLock(hBufWr);

                    nVerifyState = getverify();  // ensure that write-verify 
			is off (more speed, Scotty...)
                    setverify(0);

                    DSWriteWvfrmData(hFile, pBufWr, dwBuflen/NumChan, FIXED|16);

                    setverify(nVerifyState);  // restore write-verify state

                    GlobalUnlock(hBufWr);

                    GlobalFree(hBufWr);
                }

             // update the screen with new data

                UpdateNeeded = TRUE;
                InvalidateRect(hwnd, NULL, FALSE);
            }

            if (dwNumAcquired >= dwNumRequested) {

Done:           SendMessage(hwnd, WM_COMMAND, DS_ATC_STOPBOARD, NULL);
            }

            SendMessage(hwnd, WM_UPDATESTATUS, 0, 0L);

            break;

        default:

            return DefWindowProc(hwnd, wMsg, wParam, lParam);
    }

    return 0L;
}


Hypersignal is a registered trademark of Hyperception. Signalogic, DirectDSP, and DSPower are registered trademarks, and VDS, DirectRT, SigBook, Visual Bench, and Real-Time Convolver are trademarks of Signalogic. MATLAB is a registered trademark of The MathWorks. Telogy Networks is a registered trademark of Texas Instruments-Telogy. LabVIEW is a registered trademark of National Instruments. Windows and Visual Studio are trademarks of Microsoft.

Some of the pictures used on this website Copyright © 2002 by Daniel Speck at FreeStockPhotos.com