📄 bthlink.cxx
字号:
//
// 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.
//
/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Abstract:
Windows CE Bluetooth stack layer sample
**/
#include <windows.h>
#if defined (SDK_BUILD)
#undef CP_UTF8
#endif
#include <svsutil.hxx>
#include <pkfuncs.h>
#include <bt_debug.h>
#include <bt_tdbg.h>
#include <bt_api.h>
#include <bt_buffer.h>
#include <bt_ddi.h>
#include "bthlink.hxx"
#define DEBUG_LAYER_TRACE 0x00000040
DECLARE_DEBUG_VARS();
#define CALL_HCI_CONNECT 0x01
#define CALL_HCI_DISCONNECT 0x02
#define CALL_HCI_EVENTFILTER 0x03
// SCO baseband packet types
#define BT_PACKET_TYPE_HV1 0x0020
#define BT_PACKET_TYPE_HV2 0x0040
#define BT_PACKET_TYPE_HV3 0x0080
#define BT_LINK_TYPE_SCO 0
#define BT_LINK_TYPE_ACL 1
#define MAX_BASEBAND_CONNECTIONS 20
struct Link {
Link *pNext;
BD_ADDR b;
unsigned short h;
HANDLE hProcOwner;
};
struct SCall {
SCall *pNext;
HANDLE hEvent;
HANDLE hProcOwner;
int iResult;
unsigned int fWhat : 8;
SCall (void) {
memset (this, 0, sizeof(*this));
}
};
static int bthlink_CloseDriverInstance (void);
static int bthlink_ConnectionCompleteEvent (void *pUserContext, void *pCallContext, unsigned char status, unsigned short connection_handle, BD_ADDR *pba, unsigned char link_type, unsigned char encryption_mode);
static int bthlink_DisconnectionCompleteEvent (void *pUserContext, void *pCallContext, unsigned char status, unsigned short connection_handle, unsigned char reason);
static int bthlink_hStackEvent (void *pUserContext, int iEvent, void *pEventContext);
static int bthlink_SetEventFilter_Out (void *pCallContext, unsigned char status);
static int bthlink_CreateConnection_Out (void *pCallContext, unsigned char status);
static int bthlink_Disconnect_Out (void *pCallContext, unsigned char status);
static int bthlink_hCallAborted (void *pCallContext, int iError);
class BTHLINK : public SVSSynch, public SVSRefObj {
public:
SCall *pCalls;
Link *pLinks;
unsigned int fIsRunning : 1;
unsigned int fConnected : 1;
HANDLE hHCI;
HCI_INTERFACE hci_if;
BTHLINK (void) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Initializing\n"));
pLinks = NULL;
pCalls = NULL;
fIsRunning = FALSE;
fConnected = FALSE;
hHCI = NULL;
HCI_EVENT_INDICATION hei;
memset (&hei, 0, sizeof (hei));
hei.hci_ConnectionCompleteEvent = bthlink_ConnectionCompleteEvent;
hei.hci_DisconnectionCompleteEvent = bthlink_DisconnectionCompleteEvent;
hei.hci_StackEvent = bthlink_hStackEvent;
HCI_CALLBACKS hc;
memset (&hc, 0, sizeof (hc));
hc.hci_CreateConnection_Out = bthlink_CreateConnection_Out;
hc.hci_Disconnect_Out = bthlink_Disconnect_Out;
hc.hci_SetEventFilter_Out = bthlink_SetEventFilter_Out;
hc.hci_CallAborted = bthlink_hCallAborted;
int cHciHeaders = 0;
int cHciTrailers = 0;
if (ERROR_SUCCESS != HCI_EstablishDeviceContext (this, BTH_CONTROL_DEVICEONLY, NULL, 0, 0, &hei, &hc, &hci_if, &cHciHeaders, &cHciTrailers, &hHCI)) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Could not create device context\n"));
return;
}
fIsRunning = TRUE;
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Init successful\n"));
}
~BTHLINK (void) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: deinitializing\n"));
if (hHCI)
HCI_CloseDeviceContext (hHCI);
}
};
static BTHLINK *gpLayerState = NULL;
//
// Auxiliary code
//
static SCall *RemoveCallFromList (void *pC) {
SCall *pParent = NULL;
SCall *pCall = gpLayerState->pCalls;
while (pCall && (pCall != pC)) {
pParent = pCall;
pCall = pCall->pNext;
}
if (! pCall)
return NULL;
if (pParent)
pParent->pNext = pCall->pNext;
else
gpLayerState->pCalls = pCall->pNext;
return pCall;
}
static void GetConnectionState (void) {
__try {
int fConnected = FALSE;
int dwRet = 0;
gpLayerState->hci_if.hci_ioctl (gpLayerState->hHCI, BTH_STACK_IOCTL_GET_CONNECTED, 0, NULL, sizeof(fConnected), (char *)&fConnected, &dwRet);
if ((dwRet == sizeof(fConnected)) && fConnected)
gpLayerState->fConnected = TRUE;
} __except (1) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK GetConnectionState : exception in hci_ioctl BTH_STACK_IOCTL_GET_CONNECTED\n"));
}
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK GetConnectionState : %s\n", gpLayerState->fConnected ? L"CONNECTED" : L"DISCONNECTED"));
}
static int StatusToError (unsigned char status, int iGeneric) {
switch (status) {
case BT_ERROR_SUCCESS:
return ERROR_SUCCESS;
case BT_ERROR_COMMAND_DISALLOWED:
case BT_ERROR_UNKNOWN_HCI_COMMAND:
case BT_ERROR_UNSUPPORTED_FEATURE_OR_PARAMETER:
case BT_ERROR_INVALID_HCI_PARAMETER:
case BT_ERROR_UNSUPPORTED_REMOTE_FEATURE:
return ERROR_CALL_NOT_IMPLEMENTED;
case BT_ERROR_NO_CONNECTION:
return ERROR_DEVICE_NOT_CONNECTED;
case BT_ERROR_HARDWARE_FAILURE:
case BT_ERROR_UNSPECIFIED_ERROR:
return ERROR_ADAP_HDW_ERR;
case BT_ERROR_PAGE_TIMEOUT:
case BT_ERROR_CONNECTION_TIMEOUT:
case BT_ERROR_HOST_TIMEOUT:
return ERROR_TIMEOUT;
case BT_ERROR_AUTHENTICATION_FAILURE:
return ERROR_NOT_AUTHENTICATED;
case BT_ERROR_KEY_MISSING:
return ERROR_NO_USER_SESSION_KEY;
case BT_ERROR_MEMORY_FULL:
return ERROR_OUTOFMEMORY;
case BT_ERROR_MAX_NUMBER_OF_CONNECTIONS:
case BT_ERROR_MAX_NUMBER_OF_SCO_CONNECTIONS:
case BT_ERROR_MAX_NUMBER_OF_ACL_CONNECTIONS:
return ERROR_NO_SYSTEM_RESOURCES;
case BT_ERROR_HOST_REJECTED_LIMITED_RESOURCES:
case BT_ERROR_HOST_REJECTED_SECURITY_REASONS:
case BT_ERROR_HOST_REJECTED_PERSONAL_DEVICE:
case BT_ERROR_PAIRING_NOT_ALLOWED:
return ERROR_CONNECTION_REFUSED;
case BT_ERROR_OETC_USER_ENDED:
case BT_ERROR_OETC_LOW_RESOURCES:
case BT_ERROR_OETC_POWERING_OFF:
return ERROR_GRACEFUL_DISCONNECT;
case BT_ERROR_CONNECTION_TERMINATED_BY_LOCAL_HOST:
return ERROR_CONNECTION_ABORTED;
case BT_ERROR_REPEATED_ATTEMPTS:
return ERROR_CONNECTION_COUNT_LIMIT;
}
return iGeneric;
}
static BTHLINK *CreateNewState (void) {
return new BTHLINK;
}
static DWORD WINAPI StackDisconnect (LPVOID lpVoid) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Disconnecting stack\n"));
bthlink_CloseDriverInstance ();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackDown (LPVOID lpVoid) {
if (! gpLayerState)
return ERROR_SERVICE_NOT_ACTIVE;
gpLayerState->Lock ();
if ((! gpLayerState->fIsRunning) || (! gpLayerState->fConnected)) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Down received :: already down\n"));
gpLayerState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Down :: taking down\n"));
gpLayerState->fConnected = FALSE;
Link *pLink = gpLayerState->pLinks;
while (gpLayerState->pLinks) {
Link *pNext = gpLayerState->pLinks->pNext;
delete gpLayerState->pLinks;
gpLayerState->pLinks = pNext;
}
SCall *pC = gpLayerState->pCalls;
gpLayerState->pCalls = NULL;
while (pC) {
SCall *pNext = pC->pNext;
pC->iResult = ERROR_SHUTDOWN_IN_PROGRESS;
pC->pNext = NULL;
SetEvent (pC->hEvent);
pC = pNext;
}
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Is Down\n"));
gpLayerState->Unlock ();
return ERROR_SUCCESS;
}
static DWORD WINAPI StackUp (LPVOID lpVoid) {
if (! gpLayerState)
return ERROR_SERVICE_NOT_ACTIVE;
gpLayerState->Lock ();
if ((! gpLayerState->fIsRunning) || gpLayerState->fConnected) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Up received :: already up\n"));
gpLayerState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Stack Up received :: UP\n"));
gpLayerState->fConnected = TRUE;
gpLayerState->Unlock ();
return ERROR_SUCCESS;
}
static void ProcessExited (HANDLE hProc) {
if (! gpLayerState)
return;
gpLayerState->Lock ();
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited : 0x%08x\n", hProc));
if (! gpLayerState->fIsRunning) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: in shutdown\n", hProc));
gpLayerState->Unlock ();
return;
}
SCall *pCall = gpLayerState->pCalls;
SCall *pCallParent = NULL;
while (pCall) {
if (pCall->hProcOwner == hProc) {
if (pCallParent)
pCallParent->pNext = pCall->pNext;
else
gpLayerState->pCalls = pCall->pNext;
pCall->iResult = ERROR_SHUTDOWN_IN_PROGRESS;
pCall->pNext = NULL;
SetEvent (pCall->hEvent);
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: aborted call 0x%08x %s\n", pCall, pCall->fWhat == CALL_HCI_CONNECT ? L"CONNECT" : L"DISCONNECT"));
pCall = pCallParent ? pCallParent->pNext : gpLayerState->pCalls;
continue;
}
pCallParent = pCall;
pCall = pCall->pNext;
}
Link *pLink = gpLayerState->pLinks;
Link *pParentLink = NULL;
while (pLink) {
if (pLink->hProcOwner == hProc) {
if (pParentLink)
pParentLink->pNext = pLink->pNext;
else
gpLayerState->pLinks = pLink->pNext;
unsigned short h = pLink->h;
delete pLink;
if (h) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: closing connection 0x%04x\n", h));
HANDLE hHCI = gpLayerState->hHCI;
HCI_Disconnect_In pCallback = gpLayerState->hci_if.hci_Disconnect_In;
gpLayerState->AddRef ();
gpLayerState->Unlock ();
__try {
pCallback (hHCI, NULL, h, 0x13);
} __except (1) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Process exited :: exception in hci_Disconnect_In\n"));
}
gpLayerState->Lock ();
gpLayerState->DelRef ();
pLink = gpLayerState->pLinks;
pParentLink = NULL;
continue;
}
pLink = pParentLink ? pParentLink->pNext : gpLayerState->pLinks;
continue;
} else {
pParentLink = pLink;
pLink = pLink->pNext;
}
}
gpLayerState->Unlock ();
}
//
// Callbacks -- HCI
//
static int bthlink_hCallAborted (void *pCallContext, int iError) {
if (! gpLayerState)
return ERROR_SERVICE_NOT_ACTIVE;
gpLayerState->Lock ();
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Aborted :: call 0x%08x, error %d\n", pCallContext, iError));
if (! gpLayerState->fIsRunning) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Aborted :: system shutdwon\n"));
gpLayerState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
SCall *pCall = RemoveCallFromList (pCallContext);
if (! pCall) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Aborted :: call not found\n"));
gpLayerState->Unlock ();
return ERROR_NOT_FOUND;
}
pCall->iResult = iError;
pCall->pNext = NULL;
SetEvent (pCall->hEvent);
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Call Abort :: aborted call 0x%08x %s\n", pCall, pCall->fWhat == CALL_HCI_CONNECT ? L"CONNECT" : L"DISCONNECT"));
gpLayerState->Unlock ();
return ERROR_SUCCESS;
}
static int bthlink_Disconnect_Out (void *pCallContext, unsigned char status) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Disconnect_Out :: call 0x%08x, status 0x%02x\n", pCallContext, status));
if (status != 0)
return bthlink_hCallAborted (pCallContext, StatusToError (status, ERROR_INTERNAL_ERROR));
return ERROR_SUCCESS;
}
static int bthlink_CreateConnection_Out (void *pCallContext, unsigned char status) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: Connect_Out :: call 0x%08x, status 0x%02x\n", pCallContext, status));
if (status != 0)
return bthlink_hCallAborted (pCallContext, StatusToError (status, ERROR_INTERNAL_ERROR));
return ERROR_SUCCESS;
}
static int bthlink_SetEventFilter_Out (void *pCallContext, unsigned char status) {
if (! gpLayerState)
return ERROR_SERVICE_NOT_ACTIVE;
gpLayerState->Lock ();
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: call 0x%08x, status 0x%02x\n", pCallContext, status));
if (! gpLayerState->fIsRunning) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: shutting down\n"));
gpLayerState->Unlock ();
return ERROR_SERVICE_NOT_ACTIVE;
}
SCall *pCall = RemoveCallFromList (pCallContext);
if (! pCall) {
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: no context\n"));
gpLayerState->Unlock ();
return ERROR_NOT_FOUND;
}
pCall->iResult = StatusToError (status, ERROR_PROTOCOL_UNREACHABLE);
pCall->pNext = NULL;
SetEvent (pCall->hEvent);
IFDBG(DebugOut (DEBUG_LAYER_TRACE, L"BTHLINK :: SetEventFilterOut :: Completed call 0x%08x\n", pCall));
gpLayerState->Unlock ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -