⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iocntrl.cpp

📁 信道仿真源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////
// IOCntrl.cpp: implementation of the CIOCntrl class.
//
//////////////////////////////////////////////////////////////////////
// Copyright 2000.    Moe Wheatley AE4JY  <ae4jy@mindspring.com>
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
////////////////////////////////////////////////////////////////////////
//

#include <float.h>
#include <afxmt.h>
#include "stdafx.h"
#include "Errorcodes.h"
#include "IOCntrl.h"
#include "PathSim.h"
#include <math.h>


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


#define RMS_MAXAMPLITUDE 4000.0	//RMS amplitude out of 32768
								// pick so that worst case Gaussian noise
								// plus signals will not overflow soundcard

#define RMSAVE 20
#define DISPLAY_COUNT_VAL 25

// Non Class routine for launching the worker thread
static UINT ThreadLauncher( CIOCntrl* pIO)
{
	pIO->ProcessLoop();
	return 4;
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CIOCntrl::CIOCntrl()
{
	m_fProcThreadQuit = FALSE;
	m_pSoundDev = NULL;
	m_pWaveDev = NULL;
	m_pProcThread = NULL;
	m_pBuffer = NULL;
	m_pCfft = NULL;
	m_pNoiseGen = NULL;
	m_pDelay0Buf = NULL;
	m_pDelay1Buf = NULL;
	m_pDelay2Buf = NULL;
	m_pCPath0 = NULL;
	m_pCPath1 = NULL;
	m_pCPath2 = NULL;
	m_pCDelay = NULL;
	m_FFTBufFull = FALSE;
	m_ErrorMessage = _T("");
	m_ThreadActive = FALSE;
	m_pDoc = NULL;
	m_SSum = 0.0;
	m_SNR = 1.0;
	m_SigRMS = 0.0;
	m_SignalGain = 1.0;
	m_pCfft = new Cfft;			//create fft object
	ASSERT( m_pCfft);
	InitializeCriticalSection(&m_CriticalSection);
}

CIOCntrl::~CIOCntrl()
{
	StopIO();
	DeleteCriticalSection(&m_CriticalSection);
	if(m_pCfft)
	{
		delete m_pCfft;	
		m_pCfft = NULL;
	}

#ifdef TESTMODE
EndTest();
#endif
}

//*************************************************************************
//**************  routines exposed to the outside  ************************
//*************************************************************************

///////////////////////////////////////////////////////////////////////////
//  Stop process thread proceedure and wait for it to finish
//  Called by main program thread to signal data processing thread to stop
//	and then wait for it to stop before returning.
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::StopIO()
{
	if( m_pProcThread != NULL )		//if thread is already running
	{
		m_ThreadActive = FALSE;
		m_fProcThreadQuit = TRUE;	// stop it
		m_FFTBufFull = FALSE;
		::WaitForSingleObject(m_pProcThread->m_hThread,	2500);
		delete m_pProcThread;
		m_pProcThread = NULL;
#ifdef TESTMODE
ReadPerformance();
#endif
	}
}


///////////////////////////////////////////////////////////////////////////
//   Called to start the I/O thread running
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::StartIO(HWND h_Wnd, CPathSimDoc* pDoc)
{
	m_pDoc = pDoc;
	if( m_pProcThread == NULL)
	{
		m_ThreadActive = FALSE;
		m_hWnd = h_Wnd;
		m_fProcThreadQuit = FALSE;
		m_pProcThread = AfxBeginThread(
			(AFX_THREADPROC)ThreadLauncher,	//thread function
			(LPVOID)this,					// ptr to this class
			THREAD_PRIORITY_NORMAL, 		//give worker thread priority
			0,								// same stack size
			CREATE_SUSPENDED,				// don't let it start yet
			NULL );							// same security attributes
		m_pProcThread->m_bAutoDelete = FALSE;	// keep thread object around
		m_pProcThread->ResumeThread ();	//let er rip
	}
}



///////////////////////////////////////////////////////////////////////////
// Initializes the FFT 
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::SetFFTParams(INT ave,double gain, INT type )
{
	if(m_pCfft)
		m_pCfft->SetFFTParams( ave, gain, type );
}

///////////////////////////////////////////////////////////////////////////
// calculates FFT on latest data and put's it in users array
///////////////////////////////////////////////////////////////////////////
BOOL CIOCntrl::GetFFTData(LONG* pData, LONG start, LONG end)
{
BOOL overflo = FALSE;
	if( !m_fProcThreadQuit && (m_pCfft != NULL) && m_FFTBufFull)
	{
		EnterCriticalSection(&m_CriticalSection);
		overflo = m_pCfft->GetFFTData( start, end, pData);
		LeaveCriticalSection(&m_CriticalSection);
	}
	m_FFTBufFull = FALSE;
	return overflo;
}

///////////////////////////////////////////////////////////////////////////
// Gets latest time domain data and put's it in users array
///////////////////////////////////////////////////////////////////////////
BOOL CIOCntrl::GetTimeData1(LONG* pData, LONG start, LONG end)
{
BOOL Ovrld = FALSE;
	if( !m_fProcThreadQuit && m_pBuffer)
	{
		EnterCriticalSection(&m_CriticalSection);
		for(INT i=start; i<=end;i++)
		{
			pData[i] = (INT)m_pOutputBuf[i];
			if( pData[i] > 29491 )	//flag overload if within 10% of max
				Ovrld = TRUE;
		}
		LeaveCriticalSection(&m_CriticalSection);
	}
	return Ovrld;
}


void CIOCntrl::GetErrorMsg(CString& err)
{
	err = m_ErrorMessage;
}


void CIOCntrl::SetSNRValue(INT snrdb)
{
	EnterCriticalSection(&m_CriticalSection);
	m_SNR = pow(10, (double)snrdb/20.0);
	LeaveCriticalSection(&m_CriticalSection);
}

void CIOCntrl::ReadGains( double& Ngain, double& Sgain)
{
	EnterCriticalSection(&m_CriticalSection);
	Sgain = m_SignalGain;
	Ngain = m_NoiseRMS/RMS_MAXAMPLITUDE;
	LeaveCriticalSection(&m_CriticalSection);
}


//*************************************************************************
//**********************  local routines  *********************************
//*************************************************************************

///////////////////////////////////////////////////////////////////////////
//  Main I/O thread processing loop
///////////////////////////////////////////////////////////////////////////
void CIOCntrl::ProcessLoop()
{
//allocate double buffer for soundcard/wavefile samples
INT ErrorCode;
DWORD size;
INT numpaths = 0;
	if( (m_pBuffer = new double[sizeof(double)*BUF_SIZE]) == NULL )
		StopThread();
	if( (m_pDelay0Buf = new _complex[sizeof(_complex)*BUF_SIZE]) == NULL )
		StopThread();
	if( (m_pDelay1Buf = new _complex[sizeof(_complex)*BUF_SIZE]) == NULL )
		StopThread();
	if( (m_pDelay2Buf = new _complex[sizeof(_complex)*BUF_SIZE]) == NULL )
		StopThread();
	if(m_pDoc->m_Path0On )
		numpaths++;
	if(m_pDoc->m_Path1On )
		numpaths++;
	if(m_pDoc->m_Path2On )
		numpaths++;
	m_pCPath0 = new CPath;
	m_pCPath0->InitPath( m_pDoc->m_Spread0, m_pDoc->m_Offset0,
							BUF_SIZE, numpaths, m_pDoc->m_Path0On );
	m_pCPath1 = new CPath;
	m_pCPath1->InitPath( m_pDoc->m_Spread1, m_pDoc->m_Offset1,
							BUF_SIZE, numpaths, m_pDoc->m_Path1On );
	m_pCPath2 = new CPath;
	m_pCPath2->InitPath( m_pDoc->m_Spread2, m_pDoc->m_Offset2,
							BUF_SIZE, numpaths, m_pDoc->m_Path2On );

	m_pSoundDev = new CSound;	//create sound object
	ASSERT( m_pSoundDev);
	m_pWaveDev = new CWave;
	ASSERT( m_pWaveDev);
	// Setup Soundcard values
	m_OutWaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
	m_OutWaveFormatEx.nChannels = 1;
	m_OutWaveFormatEx.wBitsPerSample = 16;
	m_OutWaveFormatEx.nSamplesPerSec = 8000;
	m_OutWaveFormatEx.nBlockAlign = 
			m_OutWaveFormatEx.nChannels *(m_OutWaveFormatEx.wBitsPerSample/8);
	m_OutWaveFormatEx.nAvgBytesPerSec = 
			m_OutWaveFormatEx.nSamplesPerSec *	m_OutWaveFormatEx.nBlockAlign;
	m_OutWaveFormatEx.cbSize = 0;

	if( m_pDoc->m_InputSelect == USE_SOUNDCARD)
	{
		// Open Soundcard for input
		ErrorCode = m_pSoundDev->InOpen( &m_OutWaveFormatEx, BUF_SIZE,	0, -1);
		if( ErrorCode != NO_ERROR )
		{
			ProcessError( ErrorCode );
			StopThread();
		}
	}
	else
	{
		//Open wavefile for input
		ErrorCode = m_pWaveDev->InOpen( &m_pDoc->m_InFilePath, &m_InWaveFormatEx, BUF_SIZE,&size);
		if( ErrorCode != NO_ERROR )
		{
			ProcessError( ErrorCode );
			StopThread();
		}
		if( (m_InWaveFormatEx.nChannels != 1) ||
			(m_InWaveFormatEx.nSamplesPerSec != 8000) ||
			(m_InWaveFormatEx.wBitsPerSample != 16) )
		{
			ProcessError( WAVIN_ERR_OPEN );
			StopThread();
		}

	}
	m_pDoc->m_SamplesWritten = 0;
	m_DispCounter = 0;
	if(  m_pDoc->m_OutputSelect == USE_SOUNDCARD)
	{
		// Open Soundcard for output
		ErrorCode = m_pSoundDev->OutOpen( &m_OutWaveFormatEx, BUF_SIZE,0, -1);
		if( ErrorCode != NO_ERROR )
		{
			ProcessError( ErrorCode );
			StopThread();
		}
	}
	else
	{
		str = m_pDoc->m_OutFilePath;
		if( m_pDoc->m_AppendTitle )
		{
			str.Replace( _T(".") , m_pDoc->m_SimTitle + _T(".") );
		}
		ErrorCode = m_pWaveDev->OutOpen( &str, 
										&m_OutWaveFormatEx, BUF_SIZE,
										m_pDoc->m_TimeLimit*8000);
		if( ErrorCode != NO_ERROR )
		{
			ProcessError( ErrorCode );
			StopThread();
		}
	}
	if(m_pCfft)
		m_pCfft->ResetFFT();
	m_pNoiseGen = new CNoiseGen;
	if(m_pNoiseGen)
		m_pNoiseGen->InitNoiseGen();
	if(!m_pDoc->m_DirectPathActive)	//if not direct path
	{
		m_pCDelay = new CDelay;	//create delay/Hilbert filter object
		m_pCDelay->SetDelays( m_pDoc->m_Delay1, m_pDoc->m_Delay2);
	}

	m_SigRMS = RMS_MAXAMPLITUDE;
#ifdef TESTMODE
InitPerformance();
#endif
	m_ThreadActive = TRUE;
	while( !m_fProcThreadQuit )
	{
		ProcessInput();			// Get m_pBuffer with raw real input data
#ifdef TESTMODE
StartPerformance();
#endif
		ProcessSimulator();		// Process the data
#ifdef TESTMODE
StopPerformance();
#endif
		ProcessOutput();		// Output m_pBuffer real output data
	}
	Sleep(100);
	DeleteResources();		//kill all resources
}

////////////////////////////////////////////////////////////////////
// Process for Receiving audio data from soundcard
////////////////////////////////////////////////////////////////////
void CIOCntrl::ProcessInput()
{
BOOL result;
INT ErrorCode;
	if(  m_pDoc->m_InputSelect == USE_SOUNDCARD )
	{
		if( (result = m_pSoundDev->InRead( m_pBuffer, BUF_SIZE )) != BUF_SIZE)
		{
			ErrorCode = m_pSoundDev->GetError();
			if( (ErrorCode == SOUNDIN_ERR_OVERFLOW) ||
				(ErrorCode == SOUNDIN_ERR_TIMEOUT) )
			{								//cpu couldn't keep up
											// so try again
				m_pSoundDev->InClose();
				ErrorCode = m_pSoundDev->InOpen( &m_OutWaveFormatEx, BUF_SIZE, 0, -1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -