www.pudn.com > fbt-a3-20041206.zip > BTTestDlg.cpp, change:2004-03-08,size:20477b
// Copyright (c) 2004, Antony C. Roberts
// Use of this file is subject to the terms
// described in the LICENSE.TXT file that
// accompanies this file.
//
// Your use of this file indicates your
// acceptance of the terms described in
// LICENSE.TXT.
//
// http://www.freebt.net
#include "stdafx.h"
#include "fbtutil.h"
#include "BTTest.h"
#include "BTTestDlg.h"
#include "fbtHciRoundTrip.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// One of these structs is attached to each list item
typedef struct _BTDevice
{
BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE];
BYTE PageScanRepetitionMode;
BYTE PageScanPeriodMode;
BYTE PageScanMode;
BYTE ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE];
USHORT ClockOffset;
BYTE Name[FBT_HCI_NAME_SIZE];
USHORT ConnectionHandle;
} BTDevice, *PBTDevice;
typedef struct _LogItem
{
CBTTestDlg *pThis;
BOOL bEvent;
BYTE *pBuffer;
DWORD dwLength;
} LogItem, *PLogItem;
/////////////////////////////////////////////////////////////////////////////
// CBTTestDlg dialog
CBTTestDlg::CBTTestDlg(CWnd* pParent) : CDialog(CBTTestDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CBTTestDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CBTTestDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CBTTestDlg)
DDX_Control(pDX, IDS_LMP_VERSION, m_stLMPVersion);
DDX_Control(pDX, IDS_HCI_VERSION, m_stHCIVersion);
DDX_Control(pDX, IDS_DEVICE, m_stDevice);
DDX_Control(pDX, IDS_ADDRESS, m_stAddress);
DDX_Control(pDX, IDS_MANUFACTURER, m_stManufacturer);
DDX_Control(pDX, IDE_SENDTEXT, m_edtSendText);
DDX_Control(pDX, IDL_HCI, m_lbHCI);
DDX_Control(pDX, IDL_DEVICES, m_lbDevices);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CBTTestDlg, CDialog)
//{{AFX_MSG_MAP(CBTTestDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDB_INQUIRY, OnInquiry)
ON_BN_CLICKED(IDB_GET_NAMES, OnGetNames)
ON_BN_CLICKED(IDB_CONNECT, OnConnect)
ON_BN_CLICKED(IDB_DISCONNECT, OnDisconnect)
ON_BN_CLICKED(IDB_SEND, OnSend)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_USER+1, OnInitialise)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBTTestDlg message handlers
LRESULT CBTTestDlg::OnInitialise(WPARAM wParam, LPARAM lParam)
{
// Start listening for HCI events from the HW
if (StartEventListener()!=ERROR_SUCCESS)
{
MessageBox(_T("Failed to start HCI Event Listener!"));
exit(0);
}
// Send a reset command and wait for it to complete
SendReset();
// Wait a bit to make sure the device is ready...
Sleep(1000);
FBT_HCI_READ_LOCAL_VERSION_INFORMATION_COMPLETE CommandComplete;
if (FBT_HCI_SUCCESS(SendReadLocalVersionInformation(CommandComplete)))
{
fbtLog(fbtLog_Notice, "HCI Version=%d, HCI Revsion=%d, LMP Version=%d, LMP SubVersion=%d, Manufacturer=%s",
CommandComplete.HCIVersion,
CommandComplete.HCIRevision,
CommandComplete.LMPVersion,
CommandComplete.LMPSubVersion,
GetManufacturerName(CommandComplete.Manufacturer));
m_stManufacturer.SetWindowText(GetManufacturerName(CommandComplete.Manufacturer));
CString szTemp;
szTemp.Format("%d, %d", CommandComplete.HCIVersion, CommandComplete.HCIRevision);
m_stHCIVersion.SetWindowText(szTemp);
szTemp.Format("%d, %d", CommandComplete.LMPVersion, CommandComplete.LMPSubVersion);
m_stLMPVersion.SetWindowText(szTemp);
}
// Make the device discoverable
SendWriteScanEnable(3);
// Set default connect timeout
SendWritePageTimeout(0x2000);
// Set the the class of device
BYTE ClassOfDeviceBytes[FBT_HCI_DEVICE_CLASS_SIZE]={0};
// PC
ClassOfDeviceBytes[0]=0x10;
ClassOfDeviceBytes[1]=0x01;
ClassOfDeviceBytes[2]=0x02;
fbtLog(fbtLog_Notice, _T("CBTTestDlg::OnInitDialog: Calling SendWriteClassOfDevice"));
SendWriteClassOfDevice(ClassOfDeviceBytes);
fbtLog(fbtLog_Notice, _T("CBTTestDlg::OnInitDialog: Calling SendSetEventFilter"));
// Enable connection auto-accept
BYTE Condition[FBT_HCI_MAX_CONDITION_SIZE]={0};
Condition[0]=2;
SendSetEventFilter(
FBT_HCI_FILTER_CONNECTION_SETUP,
FBT_HCI_FILTER_ALL,
Condition,
1);
// Set the Device Name
TCHAR szDeviceName[80]={0};
ZeroMemory(szDeviceName, 80);
DWORD dwLength=80;
if (GetComputerName(szDeviceName, &dwLength))
{
BYTE szLocalName[FBT_HCI_NAME_SIZE]={0};
strcpy((char*)szLocalName, szDeviceName);
SendChangeLocalName(szLocalName);
}
// Read the local BD_ADDR
BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE];
if (ReadBDADDR(BD_ADDR)==ERROR_SUCCESS)
{
CString szDevice;
szDevice.Format(_T("%02X:%02X:%02X:%02X:%02X:%02X"),
BD_ADDR[5],
BD_ADDR[4],
BD_ADDR[3],
BD_ADDR[2],
BD_ADDR[1],
BD_ADDR[0]);
m_stAddress.SetWindowText(szDevice);
}
else
fbtLog(fbtLog_Notice, _T("CBTTestDlg::OnInitDialog: Failed to read BDADDR"));
// Start the reader thread
DWORD dwThreadId=0;
CreateThread(NULL, 0, Reader, (LPVOID)this, 0, &dwThreadId);
return TRUE;
}
BOOL CBTTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CFont *font=new CFont;
font->CreateFont(
14, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
0, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
FALSE, // cStrikeOut
DEFAULT_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
FF_DONTCARE, // nPitchAndFamily
"Courier New"); // lpszFacename
m_lbHCI.SetFont(font);
fbtLogSetFile("bttest.log");
fbtLogSetLevel(255);
UINT i=0;
CString szString;
while (i<255 && !IsAttached())
{
szString.Format("\\\\.\\FbtUsb%02d", i++);
CHciRoundTrip::Attach(szString);
}
if (!IsAttached())
{
MessageBox(_T("No Bluetooth hardware detected!"));
exit(0);
}
// Retrieve the HW driver device name
fbtLog(fbtLog_Notice, _T("CBTTestDlg::OnInitDialog: Connected to device %s"), szString);
char szDeviceName[80]={0};
if (GetDeviceName(szDeviceName, 80)>0)
m_stDevice.SetWindowText(szDeviceName);
// Let the dialog finish creating itself and displaying the window
// When its done, it will process its message queue on catch WM_USER+1
PostMessage(WM_USER+1, 0, 0);
return TRUE; // return TRUE unless you set the focus to a control
}
void CBTTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
CDialog::OnSysCommand(nID, lParam);
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CBTTestDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CBTTestDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BOOL CBTTestDlg::InitBT(void)
{
return true;
}
void CBTTestDlg::OnInquiry()
{
SetCursor(LoadCursor(NULL, IDC_WAIT));
m_lbDevices.ResetContent();
SendInquiry(FBT_HCI_LAP_GIAC, 5, 0);
}
DWORD CBTTestDlg::OnInquiryComplete(BYTE Status, BYTE NumResponses)
{
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (Status!=0)
MessageBox("Inquiry failed");
else
MessageBox("Inquiry complete");
return 0;
}
DWORD CBTTestDlg::OnInquiryResult(BYTE NumResponses, BYTE BD_ADDR[FBT_HCI_VARIABLE_SIZE][FBT_HCI_BDADDR_SIZE], BYTE PageScanRepetitionMode[FBT_HCI_VARIABLE_SIZE], BYTE PageScanPeriodMode[FBT_HCI_VARIABLE_SIZE], BYTE PageScanMode[FBT_HCI_VARIABLE_SIZE], BYTE ClassOfDevice[FBT_HCI_VARIABLE_SIZE][FBT_HCI_DEVICE_CLASS_SIZE], USHORT ClockOffset[FBT_HCI_VARIABLE_SIZE])
{
CString szDevice;
int nListItem=0;
PBTDevice pBTDevice=NULL;
for (UINT i=0; i<NumResponses; i++)
{
szDevice.Format(_T("%02X:%02X:%02X:%02X:%02X:%02X"),
BD_ADDR[i][5],
BD_ADDR[i][4],
BD_ADDR[i][3],
BD_ADDR[i][2],
BD_ADDR[i][1],
BD_ADDR[i][0]);
if (m_lbDevices.FindString(-1, szDevice)==LB_ERR)
{
nListItem=m_lbDevices.AddString(szDevice);
if (nListItem!=-1)
{
pBTDevice=(PBTDevice)malloc(sizeof(BTDevice));
memset(pBTDevice, 0, sizeof(BTDevice));
memcpy(pBTDevice->BD_ADDR, BD_ADDR[i], FBT_HCI_BDADDR_SIZE);
memcpy(pBTDevice->ClassOfDevice, ClassOfDevice[i], FBT_HCI_DEVICE_CLASS_SIZE);
pBTDevice->ClockOffset=ClockOffset[i];
pBTDevice->PageScanMode=PageScanMode[i];
pBTDevice->PageScanPeriodMode=PageScanPeriodMode[i];
pBTDevice->PageScanRepetitionMode=PageScanRepetitionMode[i];
m_lbDevices.SetItemData(nListItem, (DWORD)pBTDevice);
}
}
}
return 0;
}
void CBTTestDlg::OnGetNames()
{
PBTDevice pBTDevice=NULL;
int nDevice=0;
for (int i=0; i<m_lbDevices.GetCount(); i++)
{
m_lbDevices.SetCurSel(i);
pBTDevice=NULL;
pBTDevice=(PBTDevice)m_lbDevices.GetItemData(i);
if (pBTDevice)
{
if (FBT_HCI_SUCCESS(RemoteNameRequest(
pBTDevice->BD_ADDR,
pBTDevice->PageScanRepetitionMode,
pBTDevice->PageScanMode,
pBTDevice->ClockOffset,
pBTDevice->Name)))
{
m_lbDevices.DeleteString(i);
nDevice=m_lbDevices.InsertString(i, (LPCSTR)pBTDevice->Name);
m_lbDevices.SetItemData(nDevice, (DWORD)pBTDevice);
}
else
{
MessageBox("Failed to get name");
}
}
}
MessageBox("Name retrieval complete");
}
void CBTTestDlg::OnConnect()
{
int nDevice=m_lbDevices.GetCurSel();
if (nDevice==LB_ERR)
{
MessageBox("Select a device");
return;
}
PBTDevice pBTDevice=(PBTDevice)m_lbDevices.GetItemData(nDevice);
if (pBTDevice)
{
USHORT ConnectionHandle=0;
DWORD dwReturn=CreateConnection(
pBTDevice->BD_ADDR,
FBT_HCI_PACKET_TYPE_ALL,
pBTDevice->PageScanRepetitionMode,
pBTDevice->PageScanMode,
pBTDevice->ClockOffset,
TRUE,
pBTDevice->ConnectionHandle);
CString szMsg;
if (FBT_HCI_SUCCESS(dwReturn))
{
szMsg.Format("Connected on handle 0x%04x", pBTDevice->ConnectionHandle);
MessageBox(szMsg);
}
else
{
szMsg.Format("Connect failed (%s)", GetStatusText((BYTE)dwReturn));
MessageBox(szMsg);
}
}
}
void CBTTestDlg::OnDisconnect()
{
int nDevice=m_lbDevices.GetCurSel();
if (nDevice==LB_ERR)
{
MessageBox("Select a device");
return;
}
PBTDevice pBTDevice=(PBTDevice)m_lbDevices.GetItemData(nDevice);
if (pBTDevice)
{
if (FBT_HCI_SUCCESS(Disconnect(
pBTDevice->ConnectionHandle,
FBT_HCI_REMOTE_USER_TERMINATED_CONNECTION)))
{
MessageBox("Disconnected");
}
else
{
CString szMsg;
szMsg.Format("Disconnect on handle 0x%04x failed", pBTDevice->ConnectionHandle);
MessageBox(szMsg);
pBTDevice->ConnectionHandle=0;
}
}
}
DWORD CALLBACK LogItemHandler(LPVOID lpParameter)
{
PLogItem pLogItem=(PLogItem)lpParameter;
char szBuffer[1024]={0};
char szBufferShort[10]={0};
if (pLogItem->bEvent)
sprintf(szBuffer, "E: ");
else
sprintf(szBuffer, "C: ");
for (DWORD i=0; i<pLogItem->dwLength; i++)
{
sprintf(szBufferShort, "%02x ", pLogItem->pBuffer[i]);
strcat(szBuffer, szBufferShort);
}
pLogItem->pThis->m_lbHCI.AddString(szBuffer);
free(pLogItem->pBuffer);
free(pLogItem);
return 0;
}
// Hook the Event handler so that we can log events
DWORD CBTTestDlg::OnEvent(PFBT_HCI_EVENT_HEADER pEvent, DWORD Length)
{
// This isn't particularly efficient, but this is just a test app...
// Spin a thread to handle processing the event,
// otherwise we'll hang up the dialog
PLogItem pLogItem=new LogItem;
pLogItem->pThis=this;
pLogItem->bEvent=TRUE;
pLogItem->pBuffer=(BYTE*)malloc(Length);
memcpy(pLogItem->pBuffer, pEvent, Length);
pLogItem->dwLength=Length;
DWORD dwThreadId=0;
CreateThread(NULL, 0, LogItemHandler, pLogItem, 0, &dwThreadId);
// Let the superclass do the actual handling
return CHciRoundTrip::OnEvent(pEvent, Length);
}
// Hook SendHciCommand, so that we can log the commands
DWORD CBTTestDlg::SendHciCommand(PFBT_HCI_CMD_HEADER lpCommand, DWORD dwBufferSize)
{
// This isn't particularly efficient, but this is just a test app...
// Spin a thread to handle processing the event,
// otherwise we'll hang up the dialog
PLogItem pLogItem=new LogItem;
pLogItem->pThis=this;
pLogItem->bEvent=FALSE;
pLogItem->pBuffer=(BYTE*)malloc(dwBufferSize);
memcpy(pLogItem->pBuffer, lpCommand, dwBufferSize);
pLogItem->dwLength=dwBufferSize;
DWORD dwThreadId=0;
CreateThread(NULL, 0, LogItemHandler, pLogItem, 0, &dwThreadId);
// Let the superclass do the actual handling
return CHciLocal::SendHciCommand(lpCommand, dwBufferSize);
}
BOOL CBTTestDlg::AddressToString(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], CString &szAddress)
{
szAddress.Format(_T("%02X:%02X:%02X:%02X:%02X:%02X"),
BD_ADDR[5],
BD_ADDR[4],
BD_ADDR[3],
BD_ADDR[2],
BD_ADDR[1],
BD_ADDR[0]);
return TRUE;
}
int CBTTestDlg::FindDeviceByConnectionHandle(USHORT nConnectionHandle)
{
PBTDevice pBTDevice=NULL;
int i=0;
while (i<m_lbDevices.GetCount())
{
pBTDevice=(PBTDevice)m_lbDevices.GetItemData(i);
if (pBTDevice && pBTDevice->ConnectionHandle==nConnectionHandle)
{
return i;
}
i++;
}
return -1;
}
int CBTTestDlg::FindDeviceByAddress(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE])
{
PBTDevice pBTDevice=NULL;
int i=0;
while (i<m_lbDevices.GetCount())
{
pBTDevice=(PBTDevice)m_lbDevices.GetItemData(i);
if (pBTDevice && CompareBDADDRs(BD_ADDR, pBTDevice->BD_ADDR)==0)
{
return i;
}
i++;
}
return -1;
}
DWORD CBTTestDlg::OnConnectionRequest(BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], ULONG ClassOfDevice[FBT_HCI_DEVICE_CLASS_SIZE], BYTE LinkType)
{
CString szDevice;
szDevice.Format(_T("%02X:%02X:%02X:%02X:%02X:%02X"),
BD_ADDR[5],
BD_ADDR[4],
BD_ADDR[3],
BD_ADDR[2],
BD_ADDR[1],
BD_ADDR[0]);
CString szMsg;
szMsg.Format("Connection request from %s, accept?", szDevice);
if (MessageBox(szMsg, "Connection request", MB_YESNO)==IDNO)
return 0;
SendAcceptConnectionRequest(BD_ADDR, FBT_HCI_ROLE_SLAVE);
return 1;
}
DWORD CBTTestDlg::OnConnectionComplete(BYTE nStatus, USHORT nConnectionHandle, BYTE BD_ADDR[FBT_HCI_BDADDR_SIZE], BYTE nLinkType, BYTE nEncryptionMode)
{
if (nStatus==0)
{
CString szDevice;
AddressToString(BD_ADDR, szDevice);
PBTDevice pBTDevice=NULL;
int nDevice=FindDeviceByAddress(BD_ADDR);
if (nDevice==-1)
{
int nDevice=m_lbDevices.AddString(szDevice);
if (nDevice!=LB_ERR)
{
pBTDevice=(PBTDevice)malloc(sizeof(BTDevice));
memset(pBTDevice, 0, sizeof(BTDevice));
m_lbDevices.SetItemData(nDevice, (DWORD)pBTDevice);
}
}
else
{
pBTDevice=(PBTDevice)m_lbDevices.GetItemData(nDevice);
}
memcpy(pBTDevice->BD_ADDR, BD_ADDR, FBT_HCI_BDADDR_SIZE);
pBTDevice->ConnectionHandle=nConnectionHandle;
CString szMsg;
szMsg.Format("Connected to %s", szDevice);
MessageBox(szMsg, "Device connected", MB_OK);
}
return 0;
}
DWORD CALLBACK CBTTestDlg::Reader(LPVOID lpParameter)
{
FBT_TRY
CBTTestDlg *pThis=(CBTTestDlg*)lpParameter;
BYTE pBuffer[1024]={0};
DWORD dwBytesRead=0;
char szMsg[256]={0};
char szBuf[50]={0};
DWORD i;
while (true)
{
memset(pBuffer, 0, 1024);
dwBytesRead=0;
if (pThis->GetData(pBuffer, 1024, &dwBytesRead, NULL)==ERROR_SUCCESS)
{
fbtLog(fbtLog_Verbose, "CBTTestDlg::Reader: Read %d bytes", dwBytesRead);
if (dwBytesRead>0)
{
sprintf(szMsg, "R: ");
for (i=0; i<dwBytesRead; i++)
{
sprintf(szBuf, "%02x ", ((PBYTE)pBuffer)[i]);
strcat(szMsg, szBuf);
}
if (dwBytesRead>=sizeof(FBT_HCI_DATA_PACKET))
{
PFBT_HCI_DATA_PACKET pData=(PFBT_HCI_DATA_PACKET)pBuffer;
fbtLog(fbtLog_Verbose, "CBTTestDlg::Reader: %d bytes ACL data on ConnectionHandle %02x", pData->DataLength, pData->ConnectionHandle);
int nDevice=pThis->FindDeviceByConnectionHandle(pData->ConnectionHandle);
if (nDevice!=-1)
{
PBTDevice pBTDevice=(PBTDevice)pThis->m_lbDevices.GetItemData(nDevice);
if (pBTDevice)
{
CString szDeviceName;
if (strlen((LPCSTR)(pBTDevice->Name))>0)
{
szDeviceName=(LPCSTR)(pBTDevice->Name);
}
else
{
pThis->AddressToString(pBTDevice->BD_ADDR, szDeviceName);
}
szDeviceName+=" Says \"";
szDeviceName+=(LPCSTR)pData->Data;
szDeviceName+="\"";
pThis->m_lbDevices.DeleteString(nDevice);
nDevice=pThis->m_lbDevices.AddString(szDeviceName);
pThis->m_lbDevices.SetItemData(nDevice, (DWORD)pBTDevice);
pThis->m_lbDevices.SetCurSel(nDevice);
}
else
{
fbtLog(fbtLog_Failure, "CBTTestDlg::Reader: Failed to retrieve device structure");
}
}
else
{
fbtLog(fbtLog_Failure, "CBTTestDlg::Reader: Unable to find connection handle %02x", pData->ConnectionHandle);
}
}
else
{
fbtLog(fbtLog_Failure, "CBTTestDlg::Reader: Not enough data for a valida ACL packet");
}
pThis->m_lbHCI.AddString(szMsg);
fbtLog(fbtLog_Verbose, "CBTTestDlg::Reader: %s", szMsg);
}
else
{
fbtLog(fbtLog_Failure, "CBTTestDlg::Reader: 0 bytes read");
}
}
else
fbtLog(fbtLog_Failure, "CBTTestDlg::Reader: GetData failed");
}
return 0;
FBT_CATCH_RETURN(0)
}
void CBTTestDlg::OnSend()
{
int nDevice=m_lbDevices.GetCurSel();
if (nDevice==LB_ERR)
{
MessageBox("Select a device");
return;
}
CString szSendText;
m_edtSendText.GetWindowText(szSendText);
if (szSendText.IsEmpty())
{
MessageBox("Enter some text to send");
return;
}
PBTDevice pBTDevice=(PBTDevice)m_lbDevices.GetItemData(nDevice);
if (pBTDevice)
{
USHORT dwTextLength=szSendText.GetLength();
// Allocate a data packet with enough space
DWORD dwDataLength=sizeof(FBT_HCI_DATA_PACKET)+dwTextLength;
PFBT_HCI_DATA_PACKET pData=(PFBT_HCI_DATA_PACKET)malloc(dwDataLength);
memset(pData, 0, dwDataLength);
pData->ConnectionHandle=pBTDevice->ConnectionHandle;
pData->DataLength=dwTextLength+1; // Include enough space for the terminator
pData->Broadcast=FBT_HCI_BROADCAST_POINT_TO_POINT;
pData->PacketBoundary=FBT_HCI_PACKET_BOUNDARY_START;
sprintf((char*)(pData->Data), szSendText);
DWORD dwBytesWritten=0;
if (SendData(pData, dwDataLength, &dwBytesWritten, NULL)==ERROR_SUCCESS)
{
char szBuffer[1024]={0};
char szBufferShort[10]={0};
sprintf(szBuffer, "W: ");
for (DWORD i=0; i<dwDataLength; i++)
{
sprintf(szBufferShort, "%02x ", ((PBYTE)pData)[i]);
strcat(szBuffer, szBufferShort);
}
m_lbHCI.AddString(szBuffer);
m_edtSendText.SetWindowText("");
}
else
MessageBox("Send failed");
free(pData);
}
}
void CBTTestDlg::OnOK()
{
OnSend();
}