📄 device.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 <windows.h>
#include "device.h"
#include "btagw_dbg.h"
// Global data
HANDLE g_hDevice;
HANDLE g_hThread;
HANDLE g_hParserStopEvent;
CRITICAL_SECTION g_csDevice;
BOOL g_fRinging;
DWORD WINAPI ATParserThread(LPVOID pv);
// Initialize data in device module
DWORD InitializeDevice(void)
{
InitializeCriticalSection(&g_csDevice);
g_hDevice = INVALID_HANDLE_VALUE;
return ERROR_SUCCESS;
}
// DeInitialize data in the device module
DWORD DeInitializeDevice(void)
{
DeleteCriticalSection(&g_csDevice);
return ERROR_SUCCESS;
}
// Establishes ACL connection and starts parser thread
DWORD StartDevice(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
EnterCriticalSection(&g_csDevice);
g_hParserStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (! g_hParserStopEvent) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error creating stop event for ACL connection: %d"), dwRetVal));
goto exit;
}
g_hDevice = CreateFile(L"BSP1:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (g_hDevice == INVALID_HANDLE_VALUE) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error creating ACL Connection with the headset: %d"), dwRetVal));
goto exit;
}
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: *** Established ACL connection with device ***")));
// Start thread to listen for headset messages
g_hThread = CreateThread(NULL, 0, ATParserThread, NULL, 0, NULL);
if (! g_hThread) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Error creating AT parser thread: %d"), dwRetVal));
}
exit:
// Clean up on failure
if (dwRetVal != ERROR_SUCCESS) {
if (g_hParserStopEvent) {
CloseHandle(g_hParserStopEvent);
g_hParserStopEvent = NULL;
}
if (g_hThread) {
CloseHandle(g_hThread);
g_hThread = NULL;
}
if (g_hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(g_hDevice);
g_hDevice = INVALID_HANDLE_VALUE;
}
}
LeaveCriticalSection(&g_csDevice);
return dwRetVal;
}
// Closes ACL connection and signals parser thread to stop
DWORD StopDevice(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
SetEvent(g_hParserStopEvent);
EnterCriticalSection(&g_csDevice);
if (g_hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(g_hDevice);
g_hDevice = INVALID_HANDLE_VALUE;
}
LeaveCriticalSection(&g_csDevice);
// If we are calling from any thread other than the ATParserThread
// then we have to wait for the thread to exit.
if ((DWORD)g_hThread != GetCurrentThreadId()) {
if (WaitForSingleObject(g_hThread, INFINITE) == WAIT_OBJECT_0) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: ACL connection to the headset has been successfully closed")));
}
else {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error waiting for parser thread to exit: %d")));
}
}
if (g_hThread) {
CloseHandle(g_hThread);
g_hThread = NULL;
}
if (g_hParserStopEvent) {
CloseHandle(g_hParserStopEvent);
g_hParserStopEvent = NULL;
}
return dwRetVal;
}
// Informs the device module that it is currently in a ringing state. In
// other words it is currently calling the headset.
void SetRingingState(BOOL fRinging)
{
EnterCriticalSection(&g_csDevice);
g_fRinging = fRinging;
LeaveCriticalSection(&g_csDevice);
}
// Send AT command to device
DWORD SendATCommand(char* szCommand, DWORD cdwBuf)
{
DWORD dwRetVal = ERROR_SUCCESS;
BOOL fWrite;
DWORD cdwBytesWritten = 0;
EnterCriticalSection(&g_csDevice);
// Send the AT command
fWrite = WriteFile(g_hDevice, (LPVOID)szCommand, cdwBuf, &cdwBytesWritten, NULL);
if (! fWrite) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error writing AT command to the device: %d"), dwRetVal));
}
#ifdef DEBUG
if (cdwBuf != cdwBytesWritten) {
DEBUGMSG(ZONE_WARN, (_T("BTAUDIOGW: Warning --> Send only wrote %d of %d total bytes"), cdwBytesWritten, cdwBuf));
}
#endif
LeaveCriticalSection(&g_csDevice);
return dwRetVal;
}
// Extract the volume level from the AT command string sent from the headset
DWORD GetVolumeFromATCmd(CHAR* szBuf, USHORT* pusVol)
{
DWORD dwRetVal = ERROR_SUCCESS;
CHAR* pStart;
CHAR* pEnd;
CHAR* pTmp = NULL;
// pStart will point to start of string and pEnd will advance
// to the null terminating string
pStart = pEnd = &szBuf[7];
while (*pEnd != '\r' && *pEnd != '\0') {
pEnd++;
}
if (*pEnd == '\r') {
*pEnd = '\0';
}
if (pusVol) {
*pusVol = (USHORT) strtol(pStart, &pTmp, 10);
if (pTmp != pEnd) {
dwRetVal = ERROR_INVALID_DATA;
SetLastError(dwRetVal);
*pusVol = 0;
}
}
return dwRetVal;
}
// Thread which reads commands from the headset and processes them
DWORD WINAPI ATParserThread(LPVOID pv)
{
CHAR szBuf[MAX_RECV_BUF];
DWORD cdwBytesRead = 0;
BOOL fRead;
DWORD dwRetVal;
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Entering ATParserThread")));
while (1) {
fRead = ReadFile(g_hDevice, szBuf, MAX_RECV_BUF, &cdwBytesRead, NULL);
if (fRead && cdwBytesRead) {
szBuf[cdwBytesRead] = '\0';
if (cdwBytesRead == 12 && (! strncmp(szBuf, "AT+CKPD=200\r", 12))) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Received 'AT+CKPD=200' from headset")));
if (SendATCommand("\r\nOK\r\n", 6) != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error sending the OK command: %d"), GetLastError()));
}
EnterCriticalSection(&g_csDevice);
// If we are currently ringing the headset then this is an answer.
// Otherwise, the headset has hung up.
if (g_fRinging) {
SetEvent(g_hRingAnswerEvent);
LeaveCriticalSection(&g_csDevice);
}
else {
if (g_fPcmMode) {
DeinitSco();
}
StopDevice();
DEBUGMSG(ZONE_EVENTS, (_T("BTAUDIOGW: Event Signalled --> g_hCloseEvent")));
EnterCriticalSection(&g_csData);
g_dwAGState = AG_DISCONNECTED;
if (g_hCloseEvent)
SetEvent(g_hCloseEvent);
LeaveCriticalSection(&g_csData);
LeaveCriticalSection(&g_csDevice);
break;
}
}
else if (cdwBytesRead > 8 && (! strncmp(szBuf, "AT+VGM=", 7))) {
USHORT usVol = 0;
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Received 'AT+VGM=x' from headset")));
if (SendATCommand(AT_OK, 6) != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error sending the OK command: %d"), GetLastError()));
}
if (GetVolumeFromATCmd(szBuf, &usVol) == ERROR_SUCCESS) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Mic volume changed to %d"), usVol));
g_usMicVol = usVol;
DEBUGMSG(ZONE_EVENTS, (_T("BTAUDIOGW: Event Signalled --> g_hMicVolEvent")));
EnterCriticalSection(&g_csData);
if (g_hMicVolEvent)
SetEvent(g_hMicVolEvent);
LeaveCriticalSection(&g_csData);
}
else {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error getting mic volume from AT command: %d"), GetLastError()));
}
}
else if (cdwBytesRead > 8 && (! strncmp(szBuf, "AT+VGS=", 7))) {
USHORT usVol;
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Received 'AT+VGS=x' from headset")));
if (SendATCommand(AT_OK, 6) != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error sending the OK command: %d"), GetLastError()));
}
if (GetVolumeFromATCmd(szBuf, &usVol) == ERROR_SUCCESS) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Speaker volume changed to %d"), usVol));
g_usSpkVol = usVol;
DEBUGMSG(ZONE_EVENTS, (_T("BTAUDIOGW: Event Signalled --> g_hSpkVolEvent")));
EnterCriticalSection(&g_csData);
if (g_hSpkVolEvent)
SetEvent(g_hSpkVolEvent);
LeaveCriticalSection(&g_csData);
}
else {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error getting speaker volume from AT command: %d"), GetLastError()));
}
}
else {
if (g_pfnATCmdCallback) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Received unknown command from headset - calling external handler")));
// Call external handler to process command
__try {
dwRetVal = g_pfnATCmdCallback(szBuf, cdwBytesRead);
}
__except (1) {
DEBUGMSG(ZONE_ERROR, (_T("ZONE_ERROR: Caught an exception while calling external AT Command handler")));
}
// If external handler failed to process this AT Command then let's send error back ourselves
if (dwRetVal != ERROR_SUCCESS) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Handler did not process AT Command - sending back ERROR")));
if (SendATCommand(AT_ERROR, 9) != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error sending the ERROR command: %d"), GetLastError()));
}
}
}
else {
// No external handler exists so just send an error
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Received unknown command from headset - sending back ERROR")));
if (SendATCommand(AT_ERROR, 9) != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error sending the ERROR command: %d"), GetLastError()));
}
}
}
}
else if (! fRead) {
if (WaitForSingleObject(g_hParserStopEvent, 0) == WAIT_OBJECT_0) {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: ACL Connection is closing, exiting parser thread")));
break;
}
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: ReadFile failed in ATParserThread: %d"), GetLastError()));
}
}
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Exiting ATParserThread")));
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -