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

📄 btdriverstreamread.cpp

📁 Windows CE操作系统中适用的蓝牙驱动程序
💻 CPP
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include "BTDriverStream.h"

static DWORD BTWSSReadFromWindow (PWSSBTCLIENT_CONTEXT ptrcc, BYTE *buffer, int fFirstBuffer)
{
	DWORD amountRead = READ_PORT_UCHAR(ptrcc->ioBase + (fFirstBuffer ? FIRST_RX_BUFFER_LENGTH_OFFSET : SECOND_RX_BUFFER_LENGTH_OFFSET));
	if(amountRead > RXBUFFERSIZE)
	{
		amountRead = RXBUFFERSIZE;
	}

	DWORD firstWindowRead = 0;
	if(amountRead >= RX_FIRST_WINDOW_SIZE)
	{
		firstWindowRead = RX_FIRST_WINDOW_SIZE;
	}
	else
	{
		firstWindowRead = amountRead;
	}

	DWORD secondWindowRead = 0;
	if(amountRead > RX_FIRST_WINDOW_SIZE)
	{
		//There is data in second window
		secondWindowRead = amountRead - firstWindowRead;
	}
	else
	{
		secondWindowRead = 0;
	}

	DWORD i = 0;
	unsigned char *pioBase = ptrcc->ioBase + (fFirstBuffer ? FIRST_RX_BUFFER_FIRST_WINDOW_DATA_OFFSET : SECOND_RX_BUFFER_FIRST_WINDOW_DATA_OFFSET);

	//Read from first window in first buffer
	WRITE_PORT_UCHAR(ptrcc->ioBase + CMD_REGISTER_OFFSET, SET_FIRST_RX_WINDOW);
	for(i = 0;i< firstWindowRead;i++)
	{
		*(buffer + i) = READ_PORT_UCHAR(pioBase + i);
	}

	pioBase = ptrcc->ioBase + (fFirstBuffer ? FIRST_RX_BUFFER_SECOND_WINDOW_DATA_OFFSET : SECOND_RX_BUFFER_SECOND_WINDOW_DATA_OFFSET);

	//Read from second window in first buffer
	WRITE_PORT_UCHAR(ptrcc->ioBase + CMD_REGISTER_OFFSET, SET_SECOND_RX_WINDOW);
	for(i = 0;i< secondWindowRead;i++)
	{
		*(buffer + firstWindowRead + i) = READ_PORT_UCHAR(pioBase + i);
	}

	ptrcc->currentRxBuffer = fFirstBuffer ? SECOND_RX_BUFFER : FIRST_RX_BUFFER;

	//Acknowledge interrupt
	WRITE_PORT_UCHAR(ptrcc->ioBase + INTERRUPT_REGISTER_OFFSET, fFirstBuffer ? FIRST_RX_BUFFER_READY : SECOND_RX_BUFFER_READY);
	WRITE_PORT_UCHAR(ptrcc->ioBase + CMD_REGISTER_OFFSET, fFirstBuffer ? START_FIRST_RX_BUFFER : START_SECOND_RX_BUFFER);

	return amountRead;
}

///////////////////////////////////////////////////////////////
// BTWSSSetRTSState: Tell the PCCARD to set RTS. RTS here means
// Stop/Start data flow into FPGA from BT
///////////////////////////////////////////////////////////////

int BTWSSSetRTSState(PWSSBTCLIENT_CONTEXT ptrcc, int fOn)
{
	DEBUGMSG(ZONE_TRACE, (L"WceStreamBT: BTWSSSetRTSState (%d)\r\n", fOn));

	ptrcc->controlShadowRegister &= ~RTS_BIT_MASK;//Zero out RTS 
	//Set the bit
	if (fOn) ptrcc->controlShadowRegister |= (RTS_BIT_MASK * RTS_ON_FLAG);
	else ptrcc->controlShadowRegister |= (RTS_BIT_MASK * RTS_OFF_FLAG);

	//Convert to proper bitfield here
	__try
	{
		WRITE_PORT_UCHAR(ptrcc->ioBase + CONTROL_REGISTER_OFFSET, ptrcc->controlShadowRegister  );
	} __except (1)
	{
		return FALSE;
	}

	return TRUE;
}

////////////////////////////////////////////////////////////
// RxInit: Initialize receive queues
///////////////////////////////////////////////////////////

void
RxInit(PWSSBTCLIENT_CONTEXT ptrcc)
{
	__try
	{
		WRITE_PORT_UCHAR(ptrcc->ioBase + CMD_REGISTER_OFFSET, START_FIRST_RX_BUFFER | START_SECOND_RX_BUFFER);
	} __except(1)
	{
	}
}

////////////////////////////////////////////////////////////
// BTWSSRead: A user application wants to read from us.
// Check if we can complete the request immediately
///////////////////////////////////////////////////////////

DWORD WBT_Read(DWORD dwOpenContext, LPVOID pBuffer, DWORD dwNumBytes)
{
	DEBUGMSG(ZONE_TRACE, (L"WceStreamBT: WBT_Read %d bytes\r\n", dwNumBytes));

	PWSSBTCLIENT_CONTEXT  pcc = (PWSSBTCLIENT_CONTEXT)dwOpenContext;

	EnterCriticalSection (&g_CS);

	int iTotalTimeout = 0;
	int iIntervalTimeout = 0;

	if (pcc == g_pCC)
	{
		if (pcc->fReading)
		{
			LeaveCriticalSection (&g_CS);
			return 0xffffffff;
		}

		pcc->fReading = TRUE;

		iTotalTimeout = pcc->CommTimeOuts.ReadTotalTimeoutConstant;
		if (pcc->CommTimeOuts.ReadTotalTimeoutMultiplier != MAXDWORD)
			iTotalTimeout += pcc->CommTimeOuts.ReadTotalTimeoutMultiplier * dwNumBytes;

		iIntervalTimeout = pcc->CommTimeOuts.ReadIntervalTimeout;
	}

	int iStartTime = GetTickCount ();

	DWORD dwRes = WAIT_OBJECT_0;
	DWORD read = 0;

	for ( ; ; )
	{
		if ((pcc != g_pCC) || pcc->fOverflow || (! pcc->fDriverStarted) || (! pcc->fReading))
		{
			DEBUGMSG(ZONE_ERROR, (L"WceStreamBT: Overflow detected or card removed. Failing the read.\r\n"));
			read = 0xffffffff;
			break;
		}

		DWORD read_sav = read;

		read += pcc->receiveBuffer->ReadData((BYTE *)pBuffer + read, dwNumBytes - read);
	
		if (pcc->fDriverFlowOff && (pcc->receiveBuffer->GetEmptySpace() >= RESTART_FLOW))
		{
			//we may turn on flow again
			pcc->fDriverFlowOff = FALSE;
			BTWSSSetRTSState(pcc, TRUE);
		}

		if (read == dwNumBytes)
			break;

		if ((dwRes == WAIT_TIMEOUT) && (read_sav == read))	// Interval t/o and nothing read
			break;

		HANDLE h = pcc->hReadEvent;

		int iGTC = (int)GetTickCount ();

		int iTimeout = ((iIntervalTimeout != 0) && (iIntervalTimeout != MAXDWORD)) ? iIntervalTimeout : iTotalTimeout - (iGTC - iStartTime);
		if (iTimeout > (iTotalTimeout - (iGTC - iStartTime)))
			iTimeout = iTotalTimeout - (iGTC - iStartTime);

		if (iTimeout < 0)
			break;

		pcc->iRefCnt++;

		LeaveCriticalSection (&g_CS);

		dwRes = WaitForSingleObject (h, iTimeout);

		EnterCriticalSection (&g_CS);

		if (pcc == g_pCC)
			--pcc->iRefCnt;
	}

	if (pcc == g_pCC)
	{
		pcc->fReading = FALSE;
	}

	LeaveCriticalSection (&g_CS);

	DEBUGMSG(ZONE_READ, (L"WceStreamBT: Completing a read with %d bytes\r\n",read));

	return read;
}

void
BTWSSInterruptRead(PWSSBTCLIENT_CONTEXT ptrcc, BYTE reason)	// Critical section taken
{
	BYTE buffer [RXFIFOBUFFERSIZE];
	DWORD	amountRead = 0;

	if((ptrcc->currentRxBuffer == FIRST_RX_BUFFER) && (reason & FIRST_RX_BUFFER_READY))
	{
		amountRead = BTWSSReadFromWindow (ptrcc, buffer, TRUE);
		DEBUGMSG(ZONE_INTERRUPTS, (L"WCESTREAMBT:::::::::::::::::::RX1 %d bytes\n", amountRead));
	}
	else if((ptrcc->currentRxBuffer == SECOND_RX_BUFFER) && (reason & SECOND_RX_BUFFER_READY))
	{
		amountRead = BTWSSReadFromWindow (ptrcc, buffer, FALSE);
		DEBUGMSG(ZONE_INTERRUPTS, (L"WCESTREAMBT:::::::::::::::::::RX2 %d bytes\n", amountRead));
	}
	else
	{
		// Die...
		DEBUGMSG(ZONE_ERROR, (L"WCESTREAMBT: RX %s signalled, but current is %s\r\n", (reason & FIRST_RX_BUFFER_READY) ? L"FIRST" : L"SECOND", (ptrcc->currentRxBuffer == FIRST_RX_BUFFER) ? L"FIRST" : L"SECOND"));

		//Acknowledge interrupt
		if (reason & FIRST_RX_BUFFER_READY)
		{
			WRITE_PORT_UCHAR(ptrcc->ioBase + INTERRUPT_REGISTER_OFFSET, FIRST_RX_BUFFER_READY);
			WRITE_PORT_UCHAR(ptrcc->ioBase + CMD_REGISTER_OFFSET, START_FIRST_RX_BUFFER);
		}

		if (reason & SECOND_RX_BUFFER_READY)
		{
			WRITE_PORT_UCHAR(ptrcc->ioBase + INTERRUPT_REGISTER_OFFSET, SECOND_RX_BUFFER_READY);
			WRITE_PORT_UCHAR(ptrcc->ioBase + CMD_REGISTER_OFFSET, START_SECOND_RX_BUFFER);
		}

		//
		//	I would like to drop the card, but it turns out that PCMCIA card does
		//	raise this condition on initialization. So just clean up and ignore...
		//
		//		ptrcc->fOverflow = TRUE;
		//		SetEvent (ptrcc->hWriteEvent);
		//		SetEvent (ptrcc->hReadEvent);
		//

		return;
	}

	if(amountRead == 0) return;

	DWORD spaceLeft = ptrcc->receiveBuffer->GetEmptySpace();
	if(spaceLeft >= amountRead)
	{
		//NEVER WRITE TOO MUCH DATA IN INTERRUPTHANDLER.
		ptrcc->receiveBuffer->WriteData(buffer,amountRead);
	}
	else
	{
		// Die...
		DEBUGMSG(ZONE_ERROR, (L"WCESTREAMBT: RX overflow!\r\n"));

		ptrcc->fOverflow = TRUE;
		SetEvent (ptrcc->hWriteEvent);
		SetEvent (ptrcc->hReadEvent);

		return;
	}

	if(spaceLeft <= STOP_FLOW)
	{
		//Stop flow to prevent buffer overflow
		ptrcc->fDriverFlowOff=TRUE;
		BTWSSSetRTSState(ptrcc, FALSE);
	}

	SetEvent (ptrcc->hReadEvent);
}

⌨️ 快捷键说明

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