📄 hcibcsp.cpp
字号:
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;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"Drift", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->uiDriftFactor = dwData;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"ScoWriteLowNumPackets", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->iScoWriteLowNumPackets = dwData;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"ScoWriteNumPackets", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->iScoWriteNumPackets = dwData;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"ScoWritePacketSize", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->iScoWritePacketSize = dwData;
dwData = 0;
dwSize = sizeof(dwData);
if ((RegQueryValueEx (hk, L"ScoSampleSize", NULL, &dwType, (LPBYTE)&dwData, &dwSize) == ERROR_SUCCESS) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwData)) && dwData)
pParms->iScoSampleSize = dwData;
RegCloseKey (hk);
}
#if defined (DEBUG) || defined (_DEBUG)
pParms->iReadBufferHeader = DEBUG_READ_BUFFER_HEADER;
pParms->iReadBufferTrailer = DEBUG_READ_BUFFER_TRAILER;
pParms->iWriteBufferHeader = DEBUG_WRITE_BUFFER_HEADER;
pParms->iWriteBufferTrailer = DEBUG_WRITE_BUFFER_TRAILER;
#endif
return TRUE;
}
int HCI_StartHardware (void) {
IFDBG(DebugOut (DEBUG_HCI_INIT, L"[BCSP] HCI_StartHardware\n"));
if (hFile != INVALID_HANDLE_VALUE) {
IFDBG(DebugOut (DEBUG_HCI_INIT, L"[BCSP] HCI_StartHardware (already started)\n"));
return TRUE;
}
if (! gCallback) {
IFDBG(DebugOut (DEBUG_HCI_INIT, L"[BCSP] HCI_StartHardware (not registered)\n"));
return FALSE;
}
return ERROR_SUCCESS == gCallback (DEVICE_UP, NULL);
}
int HCI_StopHardware (void) {
IFDBG(DebugOut (DEBUG_HCI_INIT, L"[BCSP] HCI_StopHardware\n"));
if (hFile == INVALID_HANDLE_VALUE) {
IFDBG(DebugOut (DEBUG_HCI_INIT, L"[BCSP] HCI_StopHardware (already stopped)\n"));
return TRUE;
}
if (! gCallback) {
IFDBG(DebugOut (DEBUG_HCI_INIT, L"[BCSP] HCI_StopHardware (not registered)\n"));
return FALSE;
}
return ERROR_SUCCESS == gCallback (DEVICE_DOWN, NULL);
}
//#error this might never be called. Init the debug somewhere else?
int HCI_SetCallback (HCI_TransportCallback pfCallback) {
gCallback = pfCallback;
if (gCallback)
DebugInit();
else
DebugDeInit();
return ERROR_SUCCESS;
}
int HCI_OpenConnection (void) {
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] HCI_OpenConnection - Started\n"));
if (hFile != INVALID_HANDLE_VALUE) {
IFDBG(DebugOut (DEBUG_HCI_TRANSPORT, L"[BCSP] HCI_OpenConnection - already open, failing.\n"));
return FALSE;
}
WCHAR szComPortName[_MAX_PATH];
wcscpy (szComPortName, DEFAULT_COM_NAME);
DWORD dwBaud = 38400;
DWORD dwThreadPriority = DEFAULT_WORKER_THREAD_PRIORITY;
HKEY hk;
if (ERROR_SUCCESS == RegOpenKeyEx (HKEY_BASE, L"software\\microsoft\\bluetooth\\hci", 0, KEY_READ, &hk)) {
DWORD dwType;
DWORD dwSize = sizeof(szComPortName);
if ((ERROR_SUCCESS == RegQueryValueEx (hk, L"Name", NULL, &dwType, (LPBYTE)szComPortName, &dwSize)) &&
(dwType == REG_SZ) && (dwSize > 0) && (dwSize < _MAX_PATH))
;
else
wcscpy (szComPortName, DEFAULT_COM_NAME);
dwSize = sizeof(dwBaud);
if ((ERROR_SUCCESS == RegQueryValueEx (hk, L"baud", NULL, &dwType, (LPBYTE)&dwBaud, &dwSize)) &&
(dwType == REG_DWORD) && (dwSize == sizeof(dwBaud)))
;
else
dwBaud = 38400;
DWORD dwData = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -