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

📄 deviceclass.cpp

📁 高速公路收费系统车道软件. 功能: 1 检测公路过往车辆 2 收费过程控制和数据采集 3 车辆信息和图片上传服务器.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	} else {
//	假如千位和十位不为零但百位为0,累加声音“零”
		if((m_clsTrans.Fare()/1000!=0)
			&&(m_clsTrans.Fare()%100/10)!=0){
			nSoundLen+=nNumber[0];
		}
	}
	nValue=(m_clsTrans.Fare()%100)/10;
	if(nValue>0){				//累计十位数字声音长度
		nSoundLen+=nNumber[nValue];
		nSoundLen+=nNumber[10];	//累计“十”声音长度
	} else {
//	假如千位或百位不为零且个位不为0,累加声音“零”
		if((m_clsTrans.Fare()/100!=0)
			&&(m_clsTrans.Fare()%10!=0)){
			nSoundLen+=nNumber[0];
		}
	}
	nValue=m_clsTrans.Fare()%10;
	switch(nValue){
	case 0:
//	假如应收金额为0,合成“免费”;否则不合成
		if(m_clsTrans.Fare()==0){
			nSoundLen+=nFree;		//累计“免费”声音长度
		}
		break;
	case 2:
//	假如应收金额为两圆,合成“两”;否则合成“二”
		if(m_clsTrans.Fare()==2){
			nSoundLen+=nNumber[13];		//累计“两”声音文件长度
		} else {
			nSoundLen+=nNumber[nValue];	//累计“二”声音文件长度
		}
		break;
	default:
		nSoundLen+=nNumber[nValue];
		break;
	}
	nSoundLen+=nRMB;					//累计“圆”声音文件
//	若上次申请的内存尚未释放,释放该内存。这种情况发生快速连续收费
//	时,若上辆车的价格尚未播放完毕,该声音文件将会有内存泄露
	if(pSoundImage!=NULL){
		delete [] pSoundImage;
		pSoundImage=NULL;
	}
//	根据要合成的声音长度申请内存
	pSoundImage=new char[nSoundLen];
	if(pSoundImage==NULL){
		SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"合成声音文件时内存不足");
		return;
	}
	memset(pSoundImage,0,nSoundLen);
//	合成车型声音文件
	memmove(pSoundImage,pClass,nClass);
	AssembleSound(pNumber[nBusClass],pSoundImage);
//	在车型和金额之间增加空格
	AssembleSound(pSpace,pSoundImage);
//	合成千位声音文件
	nValue=m_clsTrans.Fare()/1000;
	if(nValue>0){				//累计千位数字声音长度
		AssembleSound(pNumber[nValue%10],pSoundImage);
		AssembleSound(pNumber[12],pSoundImage);
	}
//	合成百位声音文件
	nValue=(m_clsTrans.Fare()%1000)/100;
	if(nValue>0){				//累计百位数字声音长度
		AssembleSound(pNumber[nValue],pSoundImage);
		AssembleSound(pNumber[11],pSoundImage);
	} else {
//	假如千位和十位不为零但百位为0,累计声音“零”
		if((m_clsTrans.Fare()/1000!=0)&&
			((m_clsTrans.Fare()%100)/10!=0)){
			AssembleSound(pNumber[0],pSoundImage);
		}
	}
//	合成十位声音文件
	nValue=(m_clsTrans.Fare()%100)/10;
	if(nValue>0){				//累计十位数字声音长度
		AssembleSound(pNumber[nValue],pSoundImage);
		AssembleSound(pNumber[10],pSoundImage);
	} else {
//	假如千位或百位不为零且个位不为零但十位为零,累计声音“零”
		if((m_clsTrans.Fare()/100!=0)&&
			(m_clsTrans.Fare()%10!=0)){
			AssembleSound(pNumber[0],pSoundImage);
		}
	}
	nValue=m_clsTrans.Fare()%10;
	switch(nValue){
	case 0:
//	假如应收金额为0,合成“免费”;否则不合成
		if(m_clsTrans.Fare()==0){
			AssembleSound(pFree,pSoundImage);
		}
		break;
	case 2:
//	假如应收金额为两圆,合成“两”;否则合成“二”
		if(m_clsTrans.Fare()==2){
			AssembleSound(pNumber[13],pSoundImage);
		} else {
			AssembleSound(pNumber[nValue],pSoundImage);
		}
		break;
	default:
		AssembleSound(pNumber[nValue],pSoundImage);
		break;
	}
//	累计“圆”声音文件
	if(m_clsTrans.Fare()!=0){
		AssembleSound(pRMB,pSoundImage);
	}
	try{
		sndPlaySound(pSoundImage,SND_MEMORY|SND_ASYNC);
//	启动定时器,定时器超时后清除合成的声音数据
//	合成的声音文件播放时间 = 数据长度 / 每秒的字节数,对WAV
//	文件,每秒的字节数固定位于第29 - 32字节
		DWORD nAvgBytesPerSec=0;
		memmove(&nAvgBytesPerSec,pSoundImage+28,sizeof(DWORD));
		DWORD nTotalTime=nSoundLen*1000/nAvgBytesPerSec+200;
		SendMessage(theApp.m_pMainWnd->m_hWnd,WM_STARTUP_TIMER,SOUND_TIMER,nTotalTime);
	}
	catch(...){
		SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"CSound::PlayFare()出现异常\n");
	}
}

//	定时器超时后删除合成的声音数据
void CSound::ProcessTimerOut()
{
	if(pSoundImage!=NULL){
		delete [] pSoundImage;
		pSoundImage=NULL;
	}
}

//	播放“祝您一路顺风”
void CSound::PlayThankYou()
{
	try{
		sndPlaySound(pThankYou,SND_MEMORY|SND_ASYNC);
	}
	catch(...){
		SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"CSound::PlayThankYou()出现异常\n");
	}
}

//	停止播放
void CSound::StopPlay()
{
	try{
		sndPlaySound(NULL,SND_ASYNC);
	}
	catch(...){
		SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"CSound::StopPlay()出现异常\n");
	}
}

//	按照实际情况重新组合并生成新的WAV文件
//	WAV文件结构应当如下所述:
//	1、Microsoft WAV文件实际上是RIFF(Resource Intercharge File 
//	   Format)数据块,RIFF数据块由四字节的标识符(对Microsoft 
//	   WAV文件,为RIFF)、四字节的数据块尺寸(不包括4字节的标识符、
//	   4字节的尺寸本身及文件未的填充字符。典型地:若文件尾无填充
//	   字符,其值等于文件长度减8)、块的数据部分、填充字符(假如
//	   数据长度为奇数,增加一个空字符作为占位符)
//	2、对Microsoft WAV文件,RIFF块的数据部分的前4个字节为WAVE,
//	   指明本RIFF块的数据格式
//	3、RIFF块内可包含几种子块:"fmt "子块、"fact"子块及"data"子块,
//	   其中"fact"子块并非必须
//	4、子块和RIFF块有相同的结构:四字节标识符、四字节数据块尺寸、
//	   块的数据部分、填充字符
//	5、"fmt "块定义音频文件的格式,四字节标识符为"fmt ",数据长度
//	   为以下结构的长度(若cbSize被忽略,则为16;否则为18),其数
//	   据块定义音频文件格式,内容如下:
//		typedef struct { 
//			WORD  wFormatTag;    	对Microsoft WAV文件,为1
//			WORD  nChannels; 		声道数:单声道为1,双声道为2
//			DWORD nSamplesPerSec; 	每秒的样本数
//			DWORD nAvgBytesPerSec; 	每秒的字节数=每秒的样本数*每个数据块的尺寸
//			WORD  nBlockAlign; 		每个数据块的尺寸=通道数*每个样本的字节数
//			WORD  wBitsPerSample; 	每个样本的位数
//			WORD  cbSize; 			指明附加在WAVEFORMATEX结构后的信息。若无附加信息,该字节应置0。对Microsoft WAV文件,该字可定义,也可被忽略
//		} WAVEFORMATEX;
//	6、"fact"块存储实际数据样本长度(并非必须),四字节标识符为
//	   "fact",数据长度一般为4字节,数据块内容为波形样本的实际长度
//	7、"data"块存储实际的波形文件的实际长度,四字节标识符为"data",
//	   数据长度为波形数据的实际长度(若存在"fact"块,则"data"的数据
//	   长度等于"fact"块的数据块内容*每个样本所占字节数),数据块内
//	   容即为实际的波形数据
void CSound::AssembleSound(char *pSrc,char *pObj)
{
//	首先判断入口参数是否合法的WAV数据
	if((pSrc==NULL)||(pObj==NULL)) return;
	DWORD nScrIndex=0;
	DWORD nObjIndex=0;
//	合法WAV文件的前4个字节必须为RIFF,第9字节开始的8字节必须为WAVEfmt 
	if(strncmp(pSrc+nScrIndex,"RIFF",4)!=0) return;
	if(strncmp(pObj+nObjIndex,"RIFF",4)!=0) return;
	nScrIndex+=4;
	nObjIndex+=4;
	DWORD nFilePosition=nObjIndex;
	DWORD nScrFileLen=ByteToDWORD(pSrc+nScrIndex);
	DWORD nObjFileLen=ByteToDWORD(pObj+nObjIndex);
	nScrIndex+=4;
	nObjIndex+=4;
	if(strncmp(pSrc+nScrIndex,"WAVEfmt ",8)!=0) return;
	if(strncmp(pObj+nObjIndex,"WAVEfmt ",8)!=0) return;
	nScrIndex+=8;
	nObjIndex+=8;
//	读取fmt数据长度
	DWORD nScrFmtLen=ByteToDWORD(pSrc+nScrIndex);
	DWORD nObjFmtLen=ByteToDWORD(pObj+nObjIndex);
	nScrIndex+=4;
	nObjIndex+=4;
//	读取声音文件格式字段并判断要合并数据格式是否相同
	WAVEFORMATEX structWave1,structWave2;
	memmove(&structWave1,pSrc+nScrIndex,sizeof(WAVEFORMATEX));
	memmove(&structWave2,pObj+nObjIndex,sizeof(WAVEFORMATEX));
	if((structWave1.wFormatTag!=1)||(structWave2.wFormatTag!=1)) return;
	if(structWave1.nChannels!=structWave2.nChannels) return;
	if(structWave1.nSamplesPerSec!=structWave2.nSamplesPerSec) return;
	if(structWave1.nAvgBytesPerSec!=structWave2.nAvgBytesPerSec) return;
	if(structWave1.nBlockAlign!=structWave2.nBlockAlign) return;
	if(structWave1.wBitsPerSample!=structWave2.wBitsPerSample) return;
//	检查是否有fact块,假如有,跳过该块的数据
	nScrIndex+=nScrFmtLen;
	nObjIndex+=nObjFmtLen;
	if(strncmp(pSrc+nScrIndex,"fact",4)==0){
		nScrIndex+=4;
		nScrFmtLen=ByteToDWORD(pSrc+nScrIndex);
		nScrIndex=nScrIndex+4+nScrFmtLen;
	}
	if(strncmp(pObj+nObjIndex,"fact",4)==0){
		nObjIndex+=4;
		nObjFmtLen=ByteToDWORD(pObj+nObjIndex);
		nObjIndex=nObjIndex+4+nObjFmtLen;
	}
//	检查是否为数据块,若否,说明文件格式错误,直接返回
	if(strncmp(pSrc+nScrIndex,"data",4)!=0) return;
	if(strncmp(pObj+nObjIndex,"data",4)!=0) return;
	nScrIndex+=4;
	nObjIndex+=4;
	DWORD nDataPosition=nObjIndex;
//	读取有效数据长度
	nScrFmtLen=ByteToDWORD(pSrc+nScrIndex);
	nObjFmtLen=ByteToDWORD(pObj+nObjIndex);
//	将源数据连接到目标数据后面
	nScrIndex+=4;						//指向源有效数据其始位置
	nObjIndex=nObjIndex+4+nObjFmtLen;	//指向目标有效数据结束位置
	memmove(pObj+nObjIndex,pSrc+nScrIndex,nScrFmtLen);
//	改变文件长度及有效数据长度
	nObjFileLen+=nScrFmtLen;
	nObjFmtLen+=nScrFmtLen;
//	假如数据长度为奇数,增加一填充符
//	以下几行导致声音文件播放时出现“波、波”声,故删除之
//	if(nObjFmtLen%2!=0){
//		nObjFileLen++;
//		nObjFmtLen++;
//	}
//	修改新生成数据的文件长度及有效数据长度
	memmove(pObj+nFilePosition,&nObjFileLen,sizeof(DWORD));
	memmove(pObj+nDataPosition,&nObjFmtLen,sizeof(DWORD));
}

UINT CSound::GetSoundLen(char *pFileName)
{
	struct _finddata_t strFileInfo;
	long hFile;
	UINT nLen=0;
	if((hFile=_findfirst(pFileName,&strFileInfo))!=-1L){
		_findclose(hFile);
		nLen=strFileInfo.size;
	}
	return nLen;
}

BOOL CSound::LoadSound(char *pFileName,char *pPointer,UINT nLen)
{
	BOOL bSuccessFlag=FALSE;;
	FILE *fp1;
	if(pPointer==NULL) return bSuccessFlag;
	memset(pPointer,0,nLen);
	if((fp1=fopen(pFileName,"rb"))!=NULL){
		fread(pPointer,1,nLen,fp1);
		fclose(fp1);
		bSuccessFlag=TRUE;
	}
	return bSuccessFlag;
}

//	将分字节存放的整数(4 byte)恢复成UINT
DWORD CSound::ByteToDWORD(char *pStr)
{
	DWORD nValue=0;
	memmove(&nValue,pStr,sizeof(DWORD));
	return nValue;
}

//	释放声音文件所占用内存
void CSound::ReleaseDevice()
{
	if(pClass!=NULL){
		delete [] pClass;
		pClass=NULL;
	}
	if(pRMB!=NULL){
		delete [] pRMB;
		pRMB=NULL;
	}
	for(int i=0;i<14;i++){
		if(pNumber[i]!=NULL){
			delete [] pNumber[i];
			pNumber[i]=NULL;
		}
	}
	if(pThankYou!=NULL){
		delete [] pThankYou;
		pThankYou=NULL;
	}
	if(pFree!=NULL){
		delete [] pFree;
		pFree=NULL;
	}
	if(pSpace!=NULL){
		delete [] pSpace;
		pSpace=NULL;
	}
	if(pSoundImage!=NULL){
		delete [] pSoundImage;
		pSoundImage=NULL;
	}
}

char CPrinter::chPrinterStatus;
BOOL CPrinter::bNormalFlag=FALSE;

CPrinter::CPrinter()
{
}

//	打印机初始化:清空打印缓冲区的数据
void CPrinter::Initial()
{
	char tmpStr[3];
	memset(tmpStr,0,3);
	tmpStr[0]=0x1b;				//清除打印缓冲区
	tmpStr[1]='@';
	SendPrintData(tmpStr,2);
	NormalFlag(TRUE);
}

//	处理打印机状态并生成相应的外设消息
void CPrinter::ProcessPrinterInfo(char Status)
{
	if(chPrinterStatus!=Status){
		chPrinterStatus=Status;
		if(chPrinterStatus==0x11){
			NormalFlag(TRUE);
		} else {
			NormalFlag(FALSE);
		}
	}
} 

//	通过并口按指定的格式打印票据
BOOL CPrinter::PrintInvoice()
{
	CTransInfo m_clsTrans;
	CLaneInfo m_clsLane;
	CStatInfo m_clsStat;
	CTimeInfo m_clsTime;
	char pBuff[PRINT_INFO_LEN];
	char strMoney[20];//汉字金额
	memset(strMoney,0,20);

	ConvertMoney(m_clsTrans.Fare(),strMoney);//将整数金额转换为汉字

//	如果已经预先打印了发票的起始部分,继续打印发票的其余部分;
//	否则打印全部发票
	UINT nPosition=0;
	if(m_clsStat.HasPrePrint()){
		memset(pBuff,0,PRINT_INFO_LEN);

		sprintf(pBuff+nPosition,"   ");
		nPosition+=3;
		memmove(pBuff+nPosition,strMoney,16);
		nPosition+=17;					//打印金额		

		sprintf(pBuff+nPosition,"%.4d/%.2d/%.2d        %.2d:%.2d",
			m_clsTime.GetYear(),m_clsTime.GetMonth(),m_clsTime.GetDay(),
			m_clsTime.GetHour(),m_clsTime.GetSecond());
		nPosition+=23;
		pBuff[nPosition]=0xc;			//换页
		nPosition++;
	} else {
		memset(pBuff,0,PRINT_INFO_LEN);
//	新程序运行时经常会造成打印机不动作,初步怀疑是清除打印缓冲区
//	造成,暂时注解该行
//	故障原因:打印车型时误将16进制的车型代码当作ASCII码放入打印缓冲区
		nPosition=0;
		pBuff[nPosition]=0x1b;			//初始化打印机
		nPosition++;
		pBuff[nPosition]='@';
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置页长度
		nPosition++;
		pBuff[nPosition]='C';
		nPosition++;
		pBuff[nPosition]=15;			//每页15行
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置底部空白量
		nPosition++;
		pBuff[nPosition]='N';
		nPosition++;
		pBuff[nPosition]=4;				//每页的底部四行为空白行
		nPosition++;
		/*
		pBuff[nPosition]=0x1b;			//设置左边空白量
		nPosition++;
		pBuff[nPosition]='I';
		nPosition++;
		pBuff[nPosition]=3;				//左边距为3
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置右边空白量
		nPosition++;
		pBuff[nPosition]='Q';
		nPosition++;
		pBuff[nPosition]=1;				//右边距为8
		nPosition++;
		*/
		pBuff[nPosition]=0x1c;			//设置汉字方式打印
		nPosition++;
		pBuff[nPosition]='&';
		nPosition++;

		m_clsLane.GetPlazaName(pBuff+nPosition);
		nPosition+=5;					//打印收费站名称		
//	打印车道号及收费员代码
		sprintf(pBuff+nPosition,"%.2d       %.5d\n\n",
			m_clsLane.LaneNO(),m_clsStat.CollectNO());
		nPosition+=15;

		sprintf(pBuff+nPosition,"\n\n");
		nPosition+=2;
		
		sprintf(pBuff+nPosition,"   ");
		nPosition+=3;
		memmove(pBuff+nPosition,strMoney,16);
		nPosition+=17;					//打印金额

		sprintf(pBuff+nPosition,"\n\n\n");
		nPosition+=3;

		sprintf(pBuff+nPosition,"%.4d/%.2d/%.2d        %.2d:%.2d",
			m_clsTime.GetYear(),m_clsTime.GetMonth(),m_clsTime.GetDay(),
			m_clsTime.GetHour(),m_clsTime.GetSecond());
		nPosition+=23;
		pBuff[nPosition]=0xc;			//换页
		nPosition++;
	}
	m_clsStat.HasPrePrint(FALSE);
	if(SendPrintData(pBuff,nPosition)){
//		m_clsStat.IncInvoiceNow(0);		//打印成功后发票号++
		return TRUE;
	}else
	{ 
		return FALSE;
	}
}

//	预打印发票:为了增加发票打印的速度,收取通行费前先预先打印出
//	固定信息部分,操作员收钱后再打印其余部分发票
void CPrinter::PrePrintInvoice()
{
//	免费车和统缴车不打印发票,为防止多次预打发票造成发票打印错误,
//	若预打发票标志置位,说明已经预打了发票,直接返回
	CStatInfo m_clsStat;
	if(m_clsStat.HasPrePrint()) return;
	CLaneInfo m_clsLane;
	if(m_clsLane.bPrePrint()){
		char pBuff[PRINT_INFO_LEN];
		memset(pBuff,0,PRINT_INFO_LEN);
//	新程序运行时经常会造成打印机不动作,初步怀疑是清除打印缓冲区
//	造成,暂时注解该行
//	故障原因:打印车型时误将16进制的车型代码当作ASCII码放入打印缓冲区
		int nPosition=0;
		pBuff[nPosition]=0x1b;			//初始化打印机
		nPosition++;
		pBuff[nPosition]=0x40;
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置页长度
		nPosition++;
		pBuff[nPosition]='C';
		nPosition++;
		pBuff[nPosition]=20;			//每页20行
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置底部空白量
		nPosition++;
		pBuff[nPosition]='N';
		nPosition++;
		pBuff[nPosition]=4;				//每页的底部四行为空白行
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置左边空白量
		nPosition++;
		/*
		pBuff[nPosition]='I';
		nPosition++;
		pBuff[nPosition]=8;				//左边距为8
		nPosition++;
		pBuff[nPosition]=0x1b;			//设置右边空白量
		nPosition++;

⌨️ 快捷键说明

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