/* ------------------------------------------------------------------------------ | APPGenMon2 | | Author : Terry Leach | Revision: 9/11/03 Initial creation Purpose : Tone generator and monitor, with dynamic sound system start/stop */ #include #include #include extern "C" { #include "APPGenMon2.h" } #include "ERROR.hpp" #include "WAVES2.hpp" #include "CHANNEL.hpp" #include "LAYLA.h" #define SLEEP(msToSleep) _sleep(msToSleep) static ERR errApp; static char szMsg[ 80 ]; /* typedef long WVFORM[ FAST_FFT_SZ ]; WVFORM wvfrmCH1; */ WAVE *waves[ LAYLA_CHNS ]; //WAVE wvCH1 ( wvfrmCH1 ); // LAYLA channel definitions CHANNEL *chMaster = NULL; // Master channel control // Output or D/A channels CHANNEL *chansDA[ LAYLA_CHNS ]; //CHANNEL ch1 ( &wvCH1 ,1 ); // Input or A/D channels CHANNEL *chansAD[ LAYLA_CHNS ]; // Array of pointers to channels on the Layla long *measMEM[ LAYLA_CHNS ]; // Array of pointers to memory which will hold incomming measurements //static long meas1[ FFT_SZ ]; // Memory to hold incomming waveforms //static CHANNEL ch_1 ( &meas1[0] ,FFT_SZ ,1 ); // We will measure on channel 1 static uint _Status = 0; // Overall application status static uint _ActiveChns = 0; // High 8 bits indicate active A/D channels, Low active D/A channels // ------------------------ // APP for GenMon // --------------------------------------------------------------------------- void APP_load( uInt16 SoundBufSZ ,uInt16 ChansToActivate ) /* | Purpose: Configures and starts the ASIO compliant sound driver. */ { float *pfZeroWave; // -------------------- errApp.Display( "APP_load: " ); _Status = 0; _ActiveChns = 0; if( !ChansToActivate ) return; if( !chMaster ) { // Create master channel object chMaster = new CHANNEL( SoundBufSZ ); // Allocate master channel object if( !chMaster ) { // If we couldn't do it, no point in going on _Status = APP_ERRMEM; return; } } pfZeroWave = new float[ SoundBufSZ ]; // Get zero wave form for D/A initialization for( int ch = LAYLA_CHNS; ch--; ) { // For all potentially active LAYLA channels if( (1 << ch) & ChansToActivate ) { // If D/A channel is in fact active waves [ ch ] = new WAVE( (uint)SoundBufSZ ); // Create a wave generator object (conversion F.P. to binary) chansDA [ ch ] = new CHANNEL( waves[ch] ,ch+1 ); // Create a D/A channel object, managing access to that channel if( !waves[ch] || !chansDA[ch] ) _Status |= APP_ERRMEM; else { _ActiveChns |= (1 << ch); if( pfZeroWave ) { memset( pfZeroWave ,0 ,SoundBufSZ * sizeof(float) ); waves [ ch ]-> modify( pfZeroWave ); // Initialize sound buffer with zeros chansDA [ ch ]-> change(); // Notify ASIO driver that new wave is available } } } else { waves [ ch ] = NULL; chansDA [ ch ] = NULL; } if( (0x100 << ch) & ChansToActivate ) { // If A/D channel is in fact active measMEM [ ch ] = new long[ SoundBufSZ ]; // Memory for making sound buf measurements chansAD [ ch ] = new CHANNEL( measMEM[ch] ,SoundBufSZ ,ch+1 ); // Create an A/D channel object if( !measMEM[ch] || !chansAD[ch] ) _Status |= APP_ERRMEM; else _ActiveChns |= (0x100 << ch); } else { measMEM [ ch ] = NULL; chansAD [ ch ] = NULL; } } if( !_Status ) { // If no allocation errors... chMaster-> go(); // Start the sound system if( chMaster-> g_Status ) // If there was a problem _ActiveChns = 0; // clear the active channel list _Status |= chMaster-> g_Status; // Record sound system status _Status |= chMaster-> g_Status ? APP_ERRSTART : APP_STARTED; // Record start operation status (application status) } else _ActiveChns = 0; if( pfZeroWave ) delete [] pfZeroWave; } // --------------------------------------------------------------------------- void APP_close ( void ) /* | Purpose: Shuts down the ASIO sound driver... this is done when all the instantiated CHANNEL objects go out of scope. */ { errApp.Display( "APP_close:" ); _Status &= APP_STARTED; for( int ch = LAYLA_CHNS; ch--; ) { if( waves [ ch ] ) delete waves [ ch ]; if( chansDA [ ch ] ) delete chansDA [ ch ]; if( chansAD [ ch ] ) delete chansAD [ ch ]; if( measMEM [ ch ] ) delete [] measMEM [ ch ]; waves [ ch ] = NULL; chansDA [ ch ] = NULL; chansAD [ ch ] = NULL; measMEM [ ch ] = NULL; } if( chMaster ) { delete chMaster; chMaster = NULL; } _Status |= chMaster-> g_Status; _Status ^= chMaster-> g_Status ? 0 : APP_STARTED; _ActiveChns = 0; } // --------------------------------------------------------------------------- void APP_TX( hWAVESDA wavesDA ,uInt16 ChangedWV ,uInt16 digitalDA ) /* | Purpose: Transmits waveform on appropriate channel. Only those waveforms which have changed are transmitted anew. INPUTS: wavesDA Handle to LabView buffers containing a new waveform to be transmitted on a D/A channel. These are in contiguous memory. ChangedWV Low 8 bits indicate which D/A channel has changed digitalDA Not used, but might eventually support outputs on the Layla's digital signal lines. */ { uint ChChk; // Used to check for valid channels // -------------- errApp.Display( "APP_TX: " ); _Status = (_Status | (APP_ERRTX | APP_TXDONE )) ^ (APP_ERRTX | APP_TXDONE ); if( !wavesDA || !ChangedWV ) return; if( !(*wavesDA)-> numWaves || !(*wavesDA)-> len ) return; ChangedWV &= 0x00FF; ChChk = ChangedWV & _ActiveChns; // Validate requested channels against active channels if( ChChk ^ ChangedWV ) // Channel mismatch _Status |= APP_ERRTX; // so set error flag // ChangedWV = ChChk; // Attempt operation only on active channels for( int ch = 0 ,LVch = 0; ch < LAYLA_CHNS; ch++ ) { // For each D/A chan on the Layla if( ((1 << ch) & ChangedWV) && chansDA[ch] ) { // If its waveform has changed AND it was activated on start up waves [ ch ]-> modify( (float *)&(*wavesDA)-> val[LVch*(*wavesDA)-> len] ); chansDA [ ch ]-> change(); // Put out the new waveform LVch++; // Kick the LabView channel counter } else if( (1 << ch) & ChangedWV ) // Skip past bogus waveform handle LVch++; } _Status |= chMaster-> g_Status; _Status |= chMaster-> g_Status ? APP_ERRTX : APP_TXDONE; } // --------------------------------------------------------------------------- void APP_Measure( hWAVESAD wavesAD ,uInt16 MeasureWV ) /* | Purpose: Makes raw binary measurment of selected A/D channels. No conversion is performed, that must be done in higher level code. INPUTS: wavesAD Handle to a set of LabView buffers in which to load the measured waveforms. MeasureWV High 8 bits indicate which A/D channels to take measurements on. */ { WAVEPTR wvp; // Wave pointer to measured waveform int32 len; // Length of the waveform to be measured int pt; // Index used to transfer data from measured waveform to LabVeiw buffer uint chCK; // Used to check for valid channels // ------------- _Status = (_Status | (APP_ERRMEAS | APP_MEASURED )) ^ (APP_ERRMEAS | APP_MEASURED ); if( !wavesAD || !MeasureWV ) return; MeasureWV &= 0xFF00; chCK = MeasureWV & _ActiveChns; // Validate requested channels against active channels if( chCK ^ MeasureWV ) // Channel mismatch _Status |= APP_ERRMEAS; // so set error flag // MeasureWV = chCK; // Attempt operation only on active channels for( int ch = 0 ,LVch = 0; ch < LAYLA_CHNS; ch++ ) { if( ((0x100 << ch) & MeasureWV) && chansAD[ch] ) { // Channel measurement requested on active channel // chansAD[ ch ]-> lock(); wvp = chansAD[ ch ]-> SegAddr( 0 ); // memcpy( &(*wavesAD)-> bitVal[ch*(*wavesAD)->len] ,wvp.pv ,chansAD[ch]-> m_WVsize*BYTES ); len = (*wavesAD)-> len; for( wvp.pv = measMEM[ch] ,pt = len; pt--; (*wavesAD)-> bitVal[ LVch*len + pt ] = wvp.pl[pt] ); // chansAD[ ch ]-> unlock(); chansAD[ ch ]-> change(); LVch++; } else if( (0x100 << ch) & MeasureWV ) // Skip past bogus measurement buffer LVch++; } _Status |= chMaster-> g_Status; _Status |= chMaster-> g_Status ? APP_ERRMEAS : APP_MEASURED; } // --------------------------------------------------------------------------- ulong APP_GetStat() /* | Purpose: Returns current application status */ { uint TempStatus; // ------------------- TempStatus = _Status; _Status |= ( APP_MEASURED | APP_TXDONE ); _Status ^= ( APP_MEASURED | APP_TXDONE ); return (TempStatus << 16) | chMaster-> Missed(); } // --------------------------------------------------------------------------- uInt16 APP_Query() /* | Purpose: Returns A/D, D/A sound buffer service status */ { return chMaster-> BufStat(); }