📄 hcibcsp.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.
//
/*++
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.
Module Name:
hcibcsp.cpp
Abstract:
Implementation of BCSP protocol
Functions:
Notes:
--*/
//#define LOCALDBG L"bcsp"
//#define FULL_BCSP_DUMP 1
#define BT_USE_CELOG 1
#include <windows.h>
#include <bt_hcip.h> // implement the functions declared here
#include <bt_debug.h>
#include <bt_tdbg.h>
#include <svsutil.hxx>
#include <bt_os.h>
#define DEFAULT_WORKER_THREAD_PRIORITY 132
#if defined (SDK_BUILD) && defined (BT_USE_CELOG)
#define CELOGSDK_FILELOG L"bcsp"
#define CELOGSDK_DEFINE 1
#include "../../../../../../../../private/osinternal/pbtools/privdbg/celog_sdk.h"
#endif
// uncomment this line if using a card that does not support BCSP link establishment
// #define BCSP_NO_LINK_ESTABLISHMENT
// these are the possible values of the Protocol ID field of the BCSP Header and their meanings
#define IO_DATA_PROTOCOL_NULL 0 /* Null protocol */
#define IO_DATA_PROTOCOL_LINK_MGT 1 /* Link Management */
#define IO_DATA_PROTOCOL_CHIP_MGT_HC 2 /* CSR Chip Mgt Host/Chip */
#define IO_DATA_PROTOCOL_CHIP_MGT_CH 3 /* CSR Chip Mgt Chip/Host */
#define IO_DATA_PROTOCOL_DEVICE_MGT 4 /* Device Manager */
#define IO_DATA_PROTOCOL_HCI_CMD_EVT 5 /* HCI Command or Event */
#define IO_DATA_PROTOCOL_HCI_ACL 6 /* HCI ACL Data */
#define IO_DATA_PROTOCOL_HCI_SCO 7 /* HCI SCO Data */
#define IO_DATA_PROTOCOL_L2CAP 8 /* L2CAP API Transport */
#define IO_DATA_PROTOCOL_RFCOMM 9 /* RFCOMM API Transport */
#define IO_DATA_PROTOCOL_SDD 10 /* SDP API Transport */
#define IO_DATA_PROTOCOL_RSVD_ID_11 11
#define IO_DATA_PROTOCOL_RSVD_ID_12 12
#define IO_DATA_PROTOCOL_RSVD_ID_13 13
#define IO_DATA_PROTOCOL_RSVD_ID_14 14
#define IO_DATA_PROTOCOL_RSVD_ID_15 15
#define SLIP_END 0xc0
#define SLIP_ESC 0xdb
#define SLIP_ESC_END 0xdc
#define SLIP_ESC_ESC 0xdd
#define SLIP_BUFFER_SIZE 256
#define BCSP_RETRY_LIMIT 20
#define BCSP_ACTIVE_TIMEOUT 250
#define BCSP_PASSIVE_TIMEOUT 1000
#define BCSP_SEQ_MASK 7
#define BCSP_WIN_SIZE 4
#define BCSP_WIN_SIZE_SCO 4
#define PACKET_SIZE_R (4095 * 2 + 8)
#define PACKET_SIZE_W (4095 * 2 + 8)
#define MAX_BUFFER_SIZE (PACKET_SIZE_W * 2)
#define DEFAULT_COM_NAME L"COM1:"
#define DEBUG_READ_BUFFER_HEADER 4
#define DEBUG_WRITE_BUFFER_HEADER 8
#define DEBUG_READ_BUFFER_TRAILER 1
#define DEBUG_WRITE_BUFFER_TRAILER 3
#define SCO_DEFAULT_SAMPLE_SIZE 8
#define SCO_DEFAULT_WRITE_LOW_NUM_PACKETS 2
#define SCO_DEFAULT_WRITE_HIGH_NUM_PACKETS 4
#define SCO_DEFAULT_PACKET_SIZE 51
DECLARE_DEBUG_VARS();
#pragma pack(push, 1)
struct BCSPHeader {
union {
unsigned char flags;
struct {
unsigned char seq : 3;
unsigned char ack : 3;
unsigned char crcPresent : 1;
unsigned char protocolType : 1;
};
};
struct {
unsigned short protocolID : 4;
unsigned short payloadLength : 12;
};
unsigned char checksum;
unsigned char GetChecksum (void) {
const unsigned char *pThis = (unsigned char *)this;
return ~(pThis[0] + pThis[1] + pThis[2]);
}
void SetChecksum (void) {
checksum = GetChecksum();
}
};
#pragma pack(pop)
class BCSPPacket {
unsigned char *pPacketData; // pPayloadData is entire SLIP-encoded packet
// length of pPacketData is 10 + slipPayloadLength
int slipPayloadLength; // slipPayloadLength is length of SLIP-encoded payload
public:
BCSPHeader header;
unsigned int fNewPacket : 1; // if true, packet has not yet been sent
unsigned int fResendPacket : 1; // if true, packet has not yet been re-sent
void SetData(const void *, int);
int WriteToCOMPort (int fUnlock);
BCSPPacket (void) {
memset (this, 0, sizeof(*this));
}
~BCSPPacket (void) {
if(pPacketData)
free (pPacketData);
}
};
struct BCSPPacketListNode {
BCSPPacket packet;
BCSPPacketListNode *next;
};
struct SerialPacket {
SerialPacket *pNext;
int cSize;
int cOffset;
unsigned char ucbuffer[1024];
};
//
// Globals and their maintenance
//
static HANDLE hFile = INVALID_HANDLE_VALUE; // handle to BCSP device
static HCI_TransportCallback gCallback = NULL;
static CRITICAL_SECTION g_csBCSP;
static HANDLE g_hWriteThreadEvent;
static HANDLE g_hWriteThread;
static HANDLE g_hCanTransmitPacket; // signaled if transmit window has empty space and choke is off
static int g_iTxSeq; // sequence number of next packet to be transmitted
static int g_iTxAck; // ack number of next packet to be transmitted
// this equals sequence number of last packet received plus one
// g_iTxAck equals rxSeq at all times
static int g_iRxAck; // last processed acknowledgement received
static int g_iRxAckLast; // last unprocessed acknowledgement received
static int g_iRxSyncs; // Number of received sync packets
static int g_iRxConfs; // Number of received sync packets
static int g_iTxUnack; // How many packets not acked
static DWORD g_dwTxAckDue; // When the next ack is due
static DWORD g_dwScoSampleSize; // Size in bits of SCO samples (e.g. 8 or 16)
static BCSPPacketListNode *g_pTransmitPackets = 0;
static BCSPPacketListNode *g_pSCOTransmitPackets = 0;
static int g_fShutDown = FALSE;
static int g_fSerialError;
static CRITICAL_SECTION g_csPackets;
static SerialPacket *g_pPackets;
static FixedMemDescr *g_pfmdPacketDescr;
static HANDLE g_hPacketReady;
static HANDLE g_hReadThread;
static int g_fCeLog = FALSE;
static void ReinitGlobals (void) {
g_hWriteThreadEvent = NULL;
g_hWriteThread = NULL;
g_hReadThread = NULL;
g_hPacketReady = NULL;
g_hCanTransmitPacket = NULL;
g_iTxSeq = 0;
g_iTxAck = 0;
g_iTxUnack = 0;
g_dwTxAckDue = 0;
g_iRxAck = 0;
g_iRxAckLast = 0;
g_iRxSyncs = 0;
g_iRxConfs = 0;
g_pTransmitPackets = NULL;
g_pSCOTransmitPackets = NULL;
g_fSerialError = FALSE;
g_pPackets = NULL;
g_pfmdPacketDescr = NULL;
}
//
// Serial IO functions
//
static int WriteCommPort (unsigned char *pBuffer, DWORD dwLen) {
DWORD dwFilledSoFar = 0;
while (dwFilledSoFar < dwLen) {
DWORD dwWrit = 0;
if ((! WriteFile (hFile, &pBuffer[dwFilledSoFar], dwLen - dwFilledSoFar, &dwWrit, NULL)) &&
(dwWrit == 0)) {
if (hFile != INVALID_HANDLE_VALUE) {
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] Error writing COM port: GetLastError = 0x%08x (%d)\n", GetLastError (), GetLastError ()));
}
return FALSE;
}
#if defined (BT_USE_CELOG)
if (g_fCeLog) {
CELOGDATAFLAGGED(TRUE, CELID_RAW_UCHAR, &pBuffer[dwFilledSoFar], (unsigned short)dwWrit, 0, CELZONE_ALWAYSON, CELOG_FLAG_RAW_OUT);
}
#endif
dwFilledSoFar += dwWrit;
}
return TRUE;
}
static DWORD WINAPI COMReadThread (LPVOID phandles) {
PurgeComm (hFile, PURGE_RXCLEAR);
if (! SetCommMask (hFile, EV_RXCHAR)) {
g_fSerialError = TRUE;
SetEvent (g_hPacketReady);
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] Failed SetCommMask in BCSP HCI Interface. GetLastError = 0x%08x\n", GetLastError ()));
return FALSE;
}
EnterCriticalSection (&g_csPackets);
SerialPacket *pPacket = ((! g_fShutDown) && g_pfmdPacketDescr) ? (SerialPacket *)svsutil_GetFixed (g_pfmdPacketDescr) : NULL;
LeaveCriticalSection (&g_csPackets);
for ( ; ; ) {
DWORD dwEvent = 0;
if (! WaitCommEvent (hFile, &dwEvent, NULL)) {
if (hFile != INVALID_HANDLE_VALUE) {
g_fSerialError = TRUE;
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] Error waiting on COM port: GetLastError = 0x%08x (%d)\n", GetLastError (), GetLastError ()));
}
SetEvent (g_hPacketReady);
return FALSE;
}
if (! SetCommMask (hFile, EV_RXCHAR)) {
if (hFile != INVALID_HANDLE_VALUE) {
g_fSerialError = TRUE;
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] Failed SetCommMask in BCSP HCI Interface. GetLastError = 0x%08x\n", GetLastError ()));
}
SetEvent (g_hPacketReady);
return FALSE;
}
if ((dwEvent & EV_RXCHAR) == 0)
continue;
EnterCriticalSection (&g_csPackets);
if (! pPacket)
pPacket = ((! g_fShutDown) && g_pfmdPacketDescr) ? (SerialPacket *)svsutil_GetFixed (g_pfmdPacketDescr) : NULL;
LeaveCriticalSection (&g_csPackets);
if (! pPacket) {
g_fSerialError = TRUE;
SetEvent (g_hPacketReady);
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] OOM in COMPortReadThread. GetLastError = 0x%08x\n", GetLastError ()));
return FALSE;
}
if ((! ReadFile (hFile, pPacket->ucbuffer, sizeof(pPacket->ucbuffer), (DWORD *)&pPacket->cSize, NULL)) &&
(pPacket->cSize == 0)) {
EnterCriticalSection (&g_csPackets);
if ((! g_fShutDown) && g_pfmdPacketDescr)
svsutil_FreeFixed (pPacket, g_pfmdPacketDescr);
LeaveCriticalSection (&g_csPackets);
if (hFile != INVALID_HANDLE_VALUE) {
g_fSerialError = TRUE;
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] Error reading COM port: GetLastError = 0x%08x (%d)\n", GetLastError (), GetLastError ()));
}
SetEvent (g_hPacketReady);
return FALSE;
}
if (pPacket->cSize) {
#if defined (FULL_BCSP_DUMP)
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] Bytes arrived:\n"));
IFDBG(DumpBuff (DEBUG_HCI_TRANSPORT, pPacket->ucbuffer, pPacket->cSize));
#endif
#if defined (BT_USE_CELOG)
if (g_fCeLog) {
CELOGDATAFLAGGED(TRUE, CELID_RAW_UCHAR, pPacket->ucbuffer, pPacket->cSize, 0, CELZONE_ALWAYSON, CELOG_FLAG_RAW_IN);
}
#endif
pPacket->cOffset = 0;
EnterCriticalSection (&g_csPackets);
pPacket->pNext = NULL;
if (! g_pPackets)
g_pPackets = pPacket;
else {
SerialPacket *pRunner = g_pPackets;
while (pRunner->pNext)
pRunner = pRunner->pNext;
pRunner->pNext = pPacket;
}
SetEvent (g_hPacketReady);
LeaveCriticalSection (&g_csPackets);
pPacket = NULL;
}
}
}
static int PushBackData (unsigned char *pBuffer, DWORD dwLen) {
SerialPacket *pPacket = (SerialPacket *)svsutil_GetFixed (g_pfmdPacketDescr);
if (! pPacket) {
g_fSerialError = TRUE;
SetEvent (g_hPacketReady);
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] OOM in PushBackData. GetLastError = 0x%08x\n", GetLastError ()));
return FALSE;
}
pPacket->cSize = dwLen;
pPacket->cOffset = 0;
memcpy(pPacket->ucbuffer, pBuffer, dwLen);
pPacket = g_pPackets;
g_pPackets = pPacket;
return TRUE;
}
static int ReadCommPort (unsigned char *pBuffer, DWORD dwLen) {
DWORD dwFilledSoFar = 0;
while (dwFilledSoFar < dwLen) {
EnterCriticalSection (&g_csPackets);
if (g_fShutDown || (hFile == INVALID_HANDLE_VALUE) || g_fSerialError) {
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] Error reading COM port (or closed) - bailing out.\n"));
LeaveCriticalSection (&g_csPackets);
return FALSE;
}
while (g_pPackets && (dwFilledSoFar < dwLen)) {
SVSUTIL_ASSERT (g_pPackets->cOffset < g_pPackets->cSize);
DWORD dwRead = g_pPackets->cSize - g_pPackets->cOffset;
if (dwRead > (dwLen - dwFilledSoFar))
dwRead = dwLen - dwFilledSoFar;
memcpy (pBuffer + dwFilledSoFar, g_pPackets->ucbuffer + g_pPackets->cOffset, dwRead);
g_pPackets->cOffset += dwRead;
dwFilledSoFar += dwRead;
if (g_pPackets->cOffset == g_pPackets->cSize) {
SerialPacket *pNext = g_pPackets->pNext;
svsutil_FreeFixed (g_pPackets, g_pfmdPacketDescr);
g_pPackets = pNext;
}
}
LeaveCriticalSection (&g_csPackets);
if (dwFilledSoFar < dwLen)
WaitForSingleObject (g_hPacketReady, INFINITE);
}
return TRUE;
}
static void CloseCommPort (void) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] CloseCommPort\n"));
if (hFile != INVALID_HANDLE_VALUE) {
#if defined (BT_USE_CELOG)
if (g_fCeLog) {
BTH_CELOG_STOP_DATA sd;
GetLocalTime (&sd.st);
CELOGDATAFLAGGED(TRUE, CELID_RAW_UCHAR, &sd, sizeof(sd), 0, CELZONE_ALWAYSON, CELOG_FLAG_STOP);
#if defined (SDK_BUILD)
CELOGSDK_STOP ();
#endif
g_fCeLog = FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -