📄 hcibcsp.cpp
字号:
BCSPPacket syncRespPacket;
syncRespPacket.SetData(syncRespPayload, 4);
syncRespPacket.header.ack = 0;
syncRespPacket.header.seq = 0;
syncRespPacket.header.crcPresent = 0;
syncRespPacket.header.payloadLength = 4;
syncRespPacket.header.protocolID = 1;
syncRespPacket.header.protocolType = 0;
const unsigned char confPayload[] = { 0xAD, 0xEF, 0xAC, 0xED };
BCSPPacket confPacket;
confPacket.SetData(confPayload, 4);
confPacket.header.ack = 0;
confPacket.header.seq = 0;
confPacket.header.crcPresent = 0;
confPacket.header.payloadLength = 4;
confPacket.header.protocolID = 1;
confPacket.header.protocolType = 0;
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPLinkEstablishmentThread : SYNC\n"));
if (syncPacket.WriteToCOMPort (FALSE)) {
int iCount = 0;
while (iCount < BCSP_RETRY_LIMIT) {
DWORD ret = WaitForMultipleObjects (2, (HANDLE *)phandles, FALSE, BCSP_PASSIVE_TIMEOUT);
if(WAIT_OBJECT_0 == ret) {
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPLinkEstablishmentThread : got SYNC-RESP, sending CONF and returning\n"));
return confPacket.WriteToCOMPort (FALSE);
} else if (WAIT_OBJECT_0 + 1 == ret) {
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPLinkEstablishmentThread : got SYNC, send SYNC-RESP\n"));
if (! syncRespPacket.WriteToCOMPort (FALSE))
break;
} else {
ASSERT (ret == WAIT_TIMEOUT);
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPLinkEstablishmentThread : timeout, resending SYNC\n"));
if (! syncPacket.WriteToCOMPort (FALSE))
break;
++iCount;
}
}
}
IFDBG(DebugOut (DEBUG_ERROR, L"[BCSP] BCSPLinkEstablishmentThread : closing port and dying\n"));
CloseCommPort ();
return FALSE;
}
static int BCSPLinkEstablishment (void) {
#ifndef BCSP_NO_LINK_ESTABLISHMENT
unsigned char payload[PACKET_SIZE_R];
BCSPHeader syncHeader;
const unsigned char syncPayload[] = { 0xDA, 0xDC, 0xED, 0xED };
const unsigned char syncRespPayload[] = { 0xAC, 0xAF, 0xEF, 0xEE };
payload[0] = 0;
HANDLE hLinkEstablishmentThreadDie = CreateEvent (NULL, TRUE, FALSE, NULL);
HANDLE hLinkEstablishmentSyncReceived = CreateEvent (NULL, FALSE, FALSE, NULL);
HANDLE handles[2] = { hLinkEstablishmentThreadDie, hLinkEstablishmentSyncReceived };
HANDLE hThread = CreateThread(NULL, 0, BCSPLinkEstablishmentThread, handles, 0, NULL);
int iRes = FALSE;
while (TRUE) {
if (! ReadFromCOMPort(&syncHeader, payload))
break;
if (syncHeader.payloadLength != 4)
continue;
if (0 == memcmp(syncPayload, payload, 4))
SetEvent(hLinkEstablishmentSyncReceived);
else if (0 == memcmp(syncRespPayload, payload, 4)) {
iRes = TRUE;
break;
}
}
SetEvent(hLinkEstablishmentThreadDie);
WaitForSingleObject (hThread, INFINITE);
CloseHandle (hThread);
CloseHandle(hLinkEstablishmentThreadDie);
CloseHandle(hLinkEstablishmentSyncReceived);
hLinkEstablishmentSyncReceived = NULL;
return iRes;
#else
return TRUE;
#endif
}
//
// Protocol procedures : transmission thread
//
static int SYNCSendPureAck (DWORD ack) {
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] SendPureAck (%d)\n", ack));
BCSPPacket packet;
packet.header.ack = ack;
packet.header.seq = 0;
packet.header.crcPresent = 0;
packet.header.payloadLength = 0;
packet.header.protocolID = 0;
packet.header.protocolType = 0;
packet.header.SetChecksum();
packet.SetData(0, 0);
return packet.WriteToCOMPort(TRUE);
}
static int BCSPProcessAcks (void) {
if (g_iRxAckLast != g_iRxAck) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPProcessAcks: got an ack for seq %d\n", g_iRxAckLast));
// find the non-new packet that corresponds to this ack
BCSPPacketListNode *pPacketListNode = g_pTransmitPackets;
while(pPacketListNode && (! pPacketListNode->packet.fNewPacket) &&
((pPacketListNode->packet.header.seq + 1) & BCSP_SEQ_MASK) != g_iRxAckLast)
pPacketListNode = pPacketListNode->next;
// if the pointer is non-zero and we have an old packet we must have the packet that
// has been acked
if(pPacketListNode && (! pPacketListNode->packet.fNewPacket)) {
// free all old packets in the transmit queue up to and including the acked packet
BCSPPacketListNode *pCurrent = g_pTransmitPackets;
g_pTransmitPackets = pPacketListNode->next;
while(pCurrent && (pCurrent != g_pTransmitPackets)) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPProcessAcks: retiring packet %d\n", pCurrent->packet.header.seq));
BCSPPacketListNode* pNext = pCurrent->next;
delete pCurrent;
pCurrent = pNext;
}
SetEvent(g_hCanTransmitPacket);
g_iRxAck = g_iRxAckLast;
return TRUE;
}
} else
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPProcessAcks: already processed for seq %d\n", g_iRxAckLast));
return FALSE; // no packet was removed
}
static DWORD WINAPI BCSPWriteThread (LPVOID) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread: spinning up...\n"));
DWORD activeTimeout = INFINITE;
int retries = BCSP_RETRY_LIMIT; // retries left to oldest packet
int fWriteError = FALSE;
while ((! g_fShutDown) && (! fWriteError)) {
DWORD ret = WaitForSingleObject (g_hWriteThreadEvent, activeTimeout);
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread : woke up @ tick %d, timeout was %d ms.\n", GetTickCount (), activeTimeout));
if (g_fShutDown) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread : shutdown detected\n"));
break;
}
InterlockedIncrement ((LONG *)&g_iRxSyncs);
while ((! g_fShutDown) && (InterlockedDecrement ((LONG *)&g_iRxSyncs) > 0)) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread : sending SYNC-RESP.\n"));
const unsigned char syncRespPayload[] = { 0xAC, 0xAF, 0xEF, 0xEE };
BCSPPacket syncRespPacket;
syncRespPacket.SetData(syncRespPayload, 4);
syncRespPacket.header.ack = 0;
syncRespPacket.header.seq = 0;
syncRespPacket.header.crcPresent = 0;
syncRespPacket.header.payloadLength = 4;
syncRespPacket.header.protocolID = 1;
syncRespPacket.header.protocolType = 0;
if (! syncRespPacket.WriteToCOMPort (FALSE)) {
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread : WriteToCOMPort failed, ERROR\n"));
fWriteError = TRUE;
break;
}
}
InterlockedIncrement ((LONG *)&g_iRxConfs);
while ((! g_fShutDown) && (InterlockedDecrement ((LONG *)&g_iRxConfs) > 0)) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread : sending CONF-RESP.\n"));
const unsigned char confRespPayload[] = { 0xde, 0xad, 0xd0, 0xd0 };
BCSPPacket confRespPacket;
confRespPacket.SetData(confRespPayload, 4);
confRespPacket.header.ack = 0;
confRespPacket.header.seq = 0;
confRespPacket.header.crcPresent = 0;
confRespPacket.header.payloadLength = 4;
confRespPacket.header.protocolID = 1;
confRespPacket.header.protocolType = 0;
if (! confRespPacket.WriteToCOMPort (FALSE)) {
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread : WriteToCOMPort failed, ERROR\n"));
fWriteError = TRUE;
break;
}
}
SVSLocalCriticalSection cs (&g_csBCSP);
if (g_fShutDown || fWriteError) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread : shutdown or write error detected\n"));
break;
}
ASSERT (GetListSize () <= BCSP_WIN_SIZE);
// Handle SCO packets first
while (1) {
BCSPPacketListNode *pSCOPacket = GetNextSCOPacket();
if (pSCOPacket) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread : Sending SCO packet\n"));
fWriteError = ! pSCOPacket->packet.WriteToCOMPort (FALSE); // This unlocks
if (fWriteError) {
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread failed on send SCO packet.\n"));
}
delete pSCOPacket; // Delete SCO packet once sent
SetEvent(g_hCanTransmitPacket);
}
else {
break;
}
}
if (BCSPProcessAcks ()) {
ret = WAIT_OBJECT_0; // the timeout doesn't matter since the oldest
// packet was acked and removed from the queue
retries = BCSP_RETRY_LIMIT;
}
// If the oldest packet timed out, resend it and all other non-new packets.
if (ret == WAIT_TIMEOUT) {
if (retries-- <= 0) {
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread: retry limit reached.\n"));
break;
}
BCSPPacketListNode *pPacketListNode = g_pTransmitPackets;
int cNumRetrans = 0;
while (pPacketListNode) {
if (pPacketListNode->packet.header.protocolType) {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread: marking seq %d for resend.\n", pPacketListNode->packet.header.seq));
pPacketListNode->packet.fResendPacket = TRUE;
if (! pPacketListNode->packet.fNewPacket)
++cNumRetrans;
}
pPacketListNode = pPacketListNode->next;
}
if (cNumRetrans == 0) // Nothing to retransmit, reset the counter
retries = BCSP_RETRY_LIMIT;
else {
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread: retry %d (%d packets).\n", retries, cNumRetrans));
}
}
// if new packets are in the transmit queue then send them off
BCSPPacketListNode *pNewPacket = NULL;
while ((! g_fShutDown) && (! fWriteError) && (pNewPacket = GetFirstPacketForSend())) {
if (pNewPacket->packet.header.protocolType) { // If reliable packet type
if (pNewPacket->packet.fNewPacket) {
pNewPacket->packet.header.seq = g_iTxSeq;
g_iTxSeq = (g_iTxSeq + 1) & BCSP_SEQ_MASK;
pNewPacket->packet.fNewPacket = FALSE;
}
pNewPacket->packet.fResendPacket = FALSE;
pNewPacket->packet.header.ack = g_iTxAck;
IFDBG(DebugOut(DEBUG_HCI_TRANSPORT, L"[BCSP] BCSPWriteThread: sending seq %d.\n", pNewPacket->packet.header.seq));
g_iTxUnack = 0;
g_dwTxAckDue = 0;
}
fWriteError = ! pNewPacket->packet.WriteToCOMPort (TRUE); // This unlocks
if (fWriteError) {
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread failed on send.\n"));
}
}
if ((! g_fShutDown) && (! fWriteError)) {
if ((!pNewPacket) || (pNewPacket->packet.header.protocolType)) {
if ((g_iTxUnack >= (BCSP_WIN_SIZE-1)) || ((g_iTxUnack > 0) && (((int)GetTickCount () - (int)g_dwTxAckDue) >= 0))) {
g_iTxUnack = 0;
g_dwTxAckDue = 0;
fWriteError = ! SYNCSendPureAck(g_iTxAck); // This unlocks
if (fWriteError) {
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread failed on ack send.\n"));
}
}
}
}
if ((! g_fShutDown) && (! fWriteError)) {
if ((!pNewPacket) || (pNewPacket->packet.header.protocolType)) {
if (g_iTxUnack) {
activeTimeout = (DWORD)((int)g_dwTxAckDue - (int)GetTickCount ());
if (activeTimeout > BCSP_ACTIVE_TIMEOUT) {
activeTimeout = 0;
IFDBG(DebugOut(DEBUG_WARN, L"[BCSP] BCSPWriteThread : active timeout reset to 0\n"));
}
}
else if (g_pTransmitPackets) {
activeTimeout = BCSP_ACTIVE_TIMEOUT;
}
else {
activeTimeout = INFINITE;
}
}
}
}
IFDBG(DebugOut(DEBUG_ERROR, L"[BCSP] BCSPWriteThread :: closing COM port and dying.\n"));
CloseCommPort (); // unblock the read...
return 0;
}
//
// Stack management functions
//
int HCI_ReadHciParameters (HCI_PARAMETERS *pParms) {
if (pParms->uiSize < sizeof (*pParms))
return FALSE;
memset (pParms, 0, sizeof(*pParms));
pParms->uiSize = sizeof(*pParms);
pParms->fInterfaceVersion = HCI_INTERFACE_VERSION_1_1;
pParms->iMaxSizeRead = PACKET_SIZE_R;
pParms->iMaxSizeWrite = PACKET_SIZE_W;
pParms->iWriteBufferHeader = 4;
pParms->iReadBufferHeader = 4;
pParms->fHardwareVersion = HCI_HARDWARE_VERSION_V_1_0_B;
pParms->uiWriteTimeout = HCI_DEFAULT_WRITE_TIMEOUT;
pParms->uiDriftFactor = HCI_DEFAULT_DRIFT;
pParms->uiFlags = 0;
pParms->iScoWriteLowNumPackets = SCO_DEFAULT_WRITE_LOW_NUM_PACKETS;
pParms->iScoWriteNumPackets = SCO_DEFAULT_WRITE_HIGH_NUM_PACKETS;
pParms->iScoWritePacketSize = SCO_DEFAULT_PACKET_SIZE;
pParms->iScoSampleSize = SCO_DEFAULT_SAMPLE_SIZE;
HKEY hk;
if (RegOpenKeyEx (HKEY_BASE, L"Software\\Microsoft\\Bluetooth\\hci", 0, KEY_READ, &hk) == ERROR_SUCCESS) {
DWORD dwType = 0;
DWORD dwData = 0;
DWORD dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"ResetDelay", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->uiResetDelay = dwData;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"SpecV10a", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->fHardwareVersion = HCI_HARDWARE_VERSION_V_1_0_A;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"SpecV11", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->fHardwareVersion = HCI_HARDWARE_VERSION_V_1_1;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"WriteTimeout", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->uiWriteTimeout = dwData;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"Flags", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->uiFlags = dwData;
dwData = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -