终于闲下来了,准备总结下之前symbian上的一些经验,也算是告一个段落吧,由于工作原因基本上有半年多没有碰symbian了,已经跟不上Nokia的发展了,新的SDK也没有下下来试试,玩玩什么新的功能什么的,惭愧啊,嘿嘿,废话不说了,开始今天的主题,这也是我觉得在任何一个新平台上开发程序最先要解决的问题――调试环境。
整个CBtSvr就完成了,其实看着代码比较多,其实就实现了两个功能。蓝牙服务如果有什么不清楚可以多看看SDK自带的那几个示例代码,还有一些nokia提供的相关文档。
由于比较习惯c的printf来打印调试信息,所以我一般实例化一个BtDbg类,然后再赋给一个全局的指针,写exe程序用全局的东西比较方便。最后封装一个BtDbg_printf来打印trace。
先说下我使用到的symbian输出trace的几种方法,一是把trace直接通过控制台输出到stdout,但是因为屏幕太小看不了几行trace,小程序还能勉强使用,trace多了就很痛苦了,虽然可以加个getchar函数其等待我按键再往下跑,不过这样使用起来还是极其的不方便;二是打到文件里面,也有一个很麻烦的问题,为了获得良好的分析环境,肯定不能在手机上直接看打出来的trace,还是因为屏幕太小,又懒得每次都需要把文件发到电脑上;三是曾经在XX论坛上看到有人使用symbian提供的调试工具好像是GDB(懒的查证了),可以在PC上调试手机上跑的程序,搞了好一阵一直都没有成功过,就放弃了。碰巧当时研究了下蓝牙相关的东西,就想到干脆自己搞个方便点的trace输出功能吧:注册一个蓝牙服务,手机上跑的程序通过这个服务把trace输出到PC上,手机做为服务器,PC做为客户端在程序每次运行时连接一下就可以了,至于PC这边的客户端完全可以用超级终端来代替,这样对我这种写EXE的人来说再好不过了。
再说下蓝牙服务的相关概念,目前支持蓝牙的手机大多会支持几个标准的蓝牙服务,比如OPP(object push profile),FTP(file transfer profile)什么的,都是两个设备之间用来相互传送资料的,也有一些蓝牙耳机、拨号上网服务,蓝牙允许用户自定义服务,以便对端设备来访问,他们都是工作于蓝牙RFCOMM层之上的,RFCOMM是一个串口仿真协议,这样可以把某一个蓝牙服务虚拟为一个串口方便程序的编写。比如在蓝牙配对完成后,PC首先会去查询对方的SDP(Service Discovery Application Profile)服务,这其中有所有对端(这里就是手机)支持的服务的详细信息,PC得到这个信息后就会显示给用户对方有哪些服务,用户可以自由的选择使用哪些服务。这里举例说明我们的DEBUG服务,PC发现了我们在手机上注册的这个DEBUG串口服务(我们注册的当然可以是串口服务,标准中叫他SPP),将其显示给用户,用户在选择连接,在蓝牙链路连接成功后PC会将其虚拟为一个PC上的串口设备,这样我们就可以通过这个串口给手机通讯了。
现在看看我们要实现的这个功能,主要就是两个功能,一是创建一个蓝牙服务,能处理pc过来的连接请求,并建立蓝牙连接,断开后继续监听等待下一次连接,第二是提供一个send函数发数据就可以了。所以我将其分为一个父类CBtSvr来处理第一个问题,再写一个BtDbg子类来处理第二个问题。
先看看CBtSvr需要实现的功能,用一个活动对象来实现
class
CBtSvr :
public
public
CActive
{
public :
// 当前服务器的状态
enum CBtBaseSvrStat {
// 空闲状态
EWaitingToGetConnection,
// 监听状态
EGettingConnection,
// 连接状态
EInConnection,
} ;
CBtSvr();
virtual ~ CBtSvr(){} ;
// 类似消息处理的主循环
virtual void RunL();
// 启动服务器
virtual int StartL();
// 关闭服务器
virtual void CloseL();
// 取消当前提交的请求
virtual void DoCancel();
// 返回服务器当先状态当前状态
inline CBtBaseSvrStat Status( void ) { return iStat; };
protected :
// socket 服务器
RSocketServ sockSvr;
// 监听socket
RSocket listenSock;
// 连接 socket
RSocket connSock;
// send状态标志
TRequestStatus iSendStatus;
// 服务的当前状态
CBtBaseSvrStat iStat;
TSockXfrLength iLen;
TInt channelNum;
protected :
// 绑定服务,留给子类实现
virtual int BindL( void ) = 0 ;
// 监听
virtual int ListenL( void );
// 接受连接请求
virtual int AcceptL( void );
// 注册蓝牙服务中的Protocol段
virtual void BuildProtocolDescriptionL(CSdpAttrValueDES * aProtocolDescriptor, TInt aPort);
// 设置蓝牙服务安全
void SetSecurityOnChannelL(TBool aAuthentication, TBool aEncryption, TBool aAuthorisation, TInt aChannel);
// 注册蓝牙服务
int RegieterBlueToothServerL( const TDesC & KServiceName, TInt KSerialClassID);
// 绑定蓝牙服务名
int BuildSerivce( const TDesC & ServiceName, TInt KSerialClassID);
};
构造函数,初始化状态并加入活动对象调度器
CBtSvr::CBtSvr()
: iStat(EWaitingToGetConnection),CActive( 0 )
{
CActiveScheduler::Add( this );
}
开启蓝牙debug服务
int CBtSvr::StartL()
{
// 如果当前状态不对或者已经提交了事件
if (iStat != EWaitingToGetConnection || IsActive()) {
return - 1 ;
}
// 建立绑定debug服务
if (BindL() < 0 ) {
return - 1 ;
}
// 开始监听
if (ListenL() < 0 ) {
listenSock.Close();
sockSvr.Close();
return - 1 ;
}
// 接受连接
if (AcceptL() < 0 ) {
listenSock.Close();
sockSvr.Close();
return - 1 ;
}
return 0 ;
}
// 监听函数
int CBtSvr::ListenL( void )
{
assert(iStat == EWaitingToGetConnection);
// 只支持一个连接
if (listenSock.Listen( 1 ) != KErrNone) {
return - 1 ;
}
return 0 ;
}
// 提交接受连接请求
int CBtSvr::AcceptL( void )
{
if (connSock.Open(sockSvr) != KErrNone) {
return - 1 ;
}
listenSock.Accept(connSock, iStatus);
iStat = EGettingConnection;
SetActive();
return 0 ;
}
// 实现CActive的doCancel函数供取消事件请求时调用
void CBtSvr::DoCancel()
{
if ( ! IsActive())
return ;
switch (iStat) {
case EGettingConnection:
listenSock.CancelAll();
break ;
case EInConnection:
connSock.CancelAll();
break ;
default :
break ;
}
}
// 服务器关闭函数
void CBtSvr::CloseL()
{
Cancel();
iStat = EWaitingToGetConnection;
listenSock.Close();
sockSvr.Close();
}
// 主事件循环
void CBtSvr::RunL()
{
if (iStatus != KErrNone) {
// 出错处理
switch (iStat) {
case EGettingConnection:
iStat = EWaitingToGetConnection;
break ;
case EInConnection:
// 可能是对端断开连接
iStat = EWaitingToGetConnection;
// 重新提交接受连接事件
AcceptL();
break ;
default :
break ;
}
}
else {
switch (iStat) {
case EGettingConnection:
// 连接建立成功
iStat = EInConnection;
break ;
case EInConnection:
// 收到数据不做任何处理
break ;
default :
break ;
}
}
}
// 这个函数是设置蓝牙服务安全,没有仔细研究,simple中搬出来
void CBtSvr::SetSecurityOnChannelL(TBool aAuthentication,
TBool aEncryption,
TBool aAuthorisation,
TInt aChannel)
{
const TUid KUidBTMobTimeObexAppValue = { 0x0 };
// a connection to the security manager
RBTMan secManager;
// a security session
RBTSecuritySettings secSettingsSession;
// define the security on this port
User::LeaveIfError(secManager.Connect());
CleanupClosePushL(secManager);
User::LeaveIfError(secSettingsSession.Open(secManager));
CleanupClosePushL(secSettingsSession);
// the security settings
TBTServiceSecurity serviceSecurity(KUidBTMobTimeObexAppValue, KSolBtRFCOMM, 0 );
// Define security requirements
serviceSecurity.SetAuthentication(aAuthentication);
serviceSecurity.SetEncryption(aEncryption);
serviceSecurity.SetAuthorisation(aAuthorisation);
serviceSecurity.SetChannelID(aChannel);
TRequestStatus status;
secSettingsSession.RegisterService(serviceSecurity, status);
User::WaitForRequest(status); // wait until the security settings are set
User::LeaveIfError(status.Int());
CleanupStack::PopAndDestroy(); // secManager
CleanupStack::PopAndDestroy(); // secSettingsSession
}
// 注册蓝牙串口服务
int CBtSvr::RegieterBlueToothServerL( const TDesC & KServiceName, TInt KSerialClassID)
{
// reg the sdp server database
RSdp sdp;
RSdpDatabase iSdpDatabase;
TSdpServRecordHandle iRecord;
// sdp服务器连接
if (sdp.Connect() != KErrNone) {
return - CNSE_SYS_ERR;
}
// 打开数据库
if (iSdpDatabase.Open(sdp) != KErrNone) {
return - CNSE_SYS_ERR;
}
// 创建一个服务
iSdpDatabase.CreateServiceRecordL(KSerialClassID, iRecord);
// add a Protocol to the record
CSdpAttrValueDES * vProtocolDescriptor = CSdpAttrValueDES::NewDESL(NULL);
CleanupStack::PushL(vProtocolDescriptor);
// 设置protocl相关信息
BuildProtocolDescriptionL(vProtocolDescriptor, channelNum);
iSdpDatabase.UpdateAttributeL(iRecord,
KSdpAttrIdProtocolDescriptorList,
* vProtocolDescriptor);
// Add 0x5 display 设置为可见
CSdpAttrValueDES * browseGroupList = CSdpAttrValueDES::NewDESL(NULL);
CleanupStack::PushL(browseGroupList);
browseGroupList
-> StartListL() // List of protocols required for this method
-> BuildUUIDL(TUUID(TUint16( 0x1002 )))
-> EndListL();
iSdpDatabase.UpdateAttributeL(iRecord, KSdpAttrIdBrowseGroupList, * browseGroupList);
CleanupStack::PopAndDestroy( 2 );
// Add a name to the record,名字
iSdpDatabase.UpdateAttributeL(iRecord,
KSdpAttrIdBasePrimaryLanguage +
KSdpAttrIdOffsetServiceName,
KServiceName);
// Add a description to the record,描述
iSdpDatabase.UpdateAttributeL(iRecord,
KSdpAttrIdBasePrimaryLanguage +
KSdpAttrIdOffsetServiceDescription,
KServiceName);
iSdpDatabase.Close();
sdp.Close();
return 0 ;
}
// 这里设置蓝牙SDP服务中的协议相关信息
void CBtSvr::BuildProtocolDescriptionL(CSdpAttrValueDES * aProtocolDescriptor, TInt aPort)
{
TBuf8 < 1 > channel;
channel.Append((TChar)aPort);
aProtocolDescriptor
-> StartListL()
-> BuildDESL()
-> StartListL() // Details of lowest level protocol
// L2CAP层之上
-> BuildUUIDL(KL2CAP)
-> EndListL()
-> BuildDESL()
-> StartListL()
-> BuildUUIDL(KRFCOMM)
// 这里是绑定的RFCOMM的端口号
-> BuildUintL(channel)
-> EndListL()
-> EndListL();
}
int CBtSvr::BuildSerivce( const TDesC & ServiceName, TInt KSerialClassID)
{
TBTSockAddr add;
int ret;
_LIT(KRFCOMM, " RFCOMM " );
// connect to server
if (sockSvr.Connect() != KErrNone) {
return - 1 ;
}
// Open a socket
if (listenSock.Open(sockSvr, KRFCOMM) != KErrNone) { // ERR_OPEN
ret = - 1 ;
goto ERR_CONN;
}
// 得到一个可用的RFCOMM端口号
listenSock.GetOpt(KRFCOMMGetAvailableServerChannel, KSolBtRFCOMM, channelNum);
add.SetPort(channelNum);
if (listenSock.Bind(add) != KErrNone) {
ret = - 1 ;
goto ERR_OPEN;
}
else {
// 设置安全信息
TRAPD(err, (SetSecurityOnChannelL(EFalse, EFalse, ETrue, channelNum)));
if (err != KErrNone) {
ret = - 1 ;
goto ERR_OPEN;
}
// 注册SDP服务
TRAP(err, (RegieterBlueToothServerL(ServiceName, KSerialClassID)));
if (err != KErrNone) {
ret = - 1 ;
goto ERR_OPEN;
}
return 0 ;
}
ERR_OPEN:
listenSock.Close();
ERR_CONN:
sockSvr.Close();
return ret;
}
{
public :
// 当前服务器的状态
enum CBtBaseSvrStat {
// 空闲状态
EWaitingToGetConnection,
// 监听状态
EGettingConnection,
// 连接状态
EInConnection,
} ;
CBtSvr();
virtual ~ CBtSvr(){} ;
// 类似消息处理的主循环
virtual void RunL();
// 启动服务器
virtual int StartL();
// 关闭服务器
virtual void CloseL();
// 取消当前提交的请求
virtual void DoCancel();
// 返回服务器当先状态当前状态
inline CBtBaseSvrStat Status( void ) { return iStat; };
protected :
// socket 服务器
RSocketServ sockSvr;
// 监听socket
RSocket listenSock;
// 连接 socket
RSocket connSock;
// send状态标志
TRequestStatus iSendStatus;
// 服务的当前状态
CBtBaseSvrStat iStat;
TSockXfrLength iLen;
TInt channelNum;
protected :
// 绑定服务,留给子类实现
virtual int BindL( void ) = 0 ;
// 监听
virtual int ListenL( void );
// 接受连接请求
virtual int AcceptL( void );
// 注册蓝牙服务中的Protocol段
virtual void BuildProtocolDescriptionL(CSdpAttrValueDES * aProtocolDescriptor, TInt aPort);
// 设置蓝牙服务安全
void SetSecurityOnChannelL(TBool aAuthentication, TBool aEncryption, TBool aAuthorisation, TInt aChannel);
// 注册蓝牙服务
int RegieterBlueToothServerL( const TDesC & KServiceName, TInt KSerialClassID);
// 绑定蓝牙服务名
int BuildSerivce( const TDesC & ServiceName, TInt KSerialClassID);
};
构造函数,初始化状态并加入活动对象调度器
CBtSvr::CBtSvr()
: iStat(EWaitingToGetConnection),CActive( 0 )
{
CActiveScheduler::Add( this );
}
开启蓝牙debug服务
int CBtSvr::StartL()
{
// 如果当前状态不对或者已经提交了事件
if (iStat != EWaitingToGetConnection || IsActive()) {
return - 1 ;
}
// 建立绑定debug服务
if (BindL() < 0 ) {
return - 1 ;
}
// 开始监听
if (ListenL() < 0 ) {
listenSock.Close();
sockSvr.Close();
return - 1 ;
}
// 接受连接
if (AcceptL() < 0 ) {
listenSock.Close();
sockSvr.Close();
return - 1 ;
}
return 0 ;
}
// 监听函数
int CBtSvr::ListenL( void )
{
assert(iStat == EWaitingToGetConnection);
// 只支持一个连接
if (listenSock.Listen( 1 ) != KErrNone) {
return - 1 ;
}
return 0 ;
}
// 提交接受连接请求
int CBtSvr::AcceptL( void )
{
if (connSock.Open(sockSvr) != KErrNone) {
return - 1 ;
}
listenSock.Accept(connSock, iStatus);
iStat = EGettingConnection;
SetActive();
return 0 ;
}
// 实现CActive的doCancel函数供取消事件请求时调用
void CBtSvr::DoCancel()
{
if ( ! IsActive())
return ;
switch (iStat) {
case EGettingConnection:
listenSock.CancelAll();
break ;
case EInConnection:
connSock.CancelAll();
break ;
default :
break ;
}
}
// 服务器关闭函数
void CBtSvr::CloseL()
{
Cancel();
iStat = EWaitingToGetConnection;
listenSock.Close();
sockSvr.Close();
}
// 主事件循环
void CBtSvr::RunL()
{
if (iStatus != KErrNone) {
// 出错处理
switch (iStat) {
case EGettingConnection:
iStat = EWaitingToGetConnection;
break ;
case EInConnection:
// 可能是对端断开连接
iStat = EWaitingToGetConnection;
// 重新提交接受连接事件
AcceptL();
break ;
default :
break ;
}
}
else {
switch (iStat) {
case EGettingConnection:
// 连接建立成功
iStat = EInConnection;
break ;
case EInConnection:
// 收到数据不做任何处理
break ;
default :
break ;
}
}
}
// 这个函数是设置蓝牙服务安全,没有仔细研究,simple中搬出来
void CBtSvr::SetSecurityOnChannelL(TBool aAuthentication,
TBool aEncryption,
TBool aAuthorisation,
TInt aChannel)
{
const TUid KUidBTMobTimeObexAppValue = { 0x0 };
// a connection to the security manager
RBTMan secManager;
// a security session
RBTSecuritySettings secSettingsSession;
// define the security on this port
User::LeaveIfError(secManager.Connect());
CleanupClosePushL(secManager);
User::LeaveIfError(secSettingsSession.Open(secManager));
CleanupClosePushL(secSettingsSession);
// the security settings
TBTServiceSecurity serviceSecurity(KUidBTMobTimeObexAppValue, KSolBtRFCOMM, 0 );
// Define security requirements
serviceSecurity.SetAuthentication(aAuthentication);
serviceSecurity.SetEncryption(aEncryption);
serviceSecurity.SetAuthorisation(aAuthorisation);
serviceSecurity.SetChannelID(aChannel);
TRequestStatus status;
secSettingsSession.RegisterService(serviceSecurity, status);
User::WaitForRequest(status); // wait until the security settings are set
User::LeaveIfError(status.Int());
CleanupStack::PopAndDestroy(); // secManager
CleanupStack::PopAndDestroy(); // secSettingsSession
}
// 注册蓝牙串口服务
int CBtSvr::RegieterBlueToothServerL( const TDesC & KServiceName, TInt KSerialClassID)
{
// reg the sdp server database
RSdp sdp;
RSdpDatabase iSdpDatabase;
TSdpServRecordHandle iRecord;
// sdp服务器连接
if (sdp.Connect() != KErrNone) {
return - CNSE_SYS_ERR;
}
// 打开数据库
if (iSdpDatabase.Open(sdp) != KErrNone) {
return - CNSE_SYS_ERR;
}
// 创建一个服务
iSdpDatabase.CreateServiceRecordL(KSerialClassID, iRecord);
// add a Protocol to the record
CSdpAttrValueDES * vProtocolDescriptor = CSdpAttrValueDES::NewDESL(NULL);
CleanupStack::PushL(vProtocolDescriptor);
// 设置protocl相关信息
BuildProtocolDescriptionL(vProtocolDescriptor, channelNum);
iSdpDatabase.UpdateAttributeL(iRecord,
KSdpAttrIdProtocolDescriptorList,
* vProtocolDescriptor);
// Add 0x5 display 设置为可见
CSdpAttrValueDES * browseGroupList = CSdpAttrValueDES::NewDESL(NULL);
CleanupStack::PushL(browseGroupList);
browseGroupList
-> StartListL() // List of protocols required for this method
-> BuildUUIDL(TUUID(TUint16( 0x1002 )))
-> EndListL();
iSdpDatabase.UpdateAttributeL(iRecord, KSdpAttrIdBrowseGroupList, * browseGroupList);
CleanupStack::PopAndDestroy( 2 );
// Add a name to the record,名字
iSdpDatabase.UpdateAttributeL(iRecord,
KSdpAttrIdBasePrimaryLanguage +
KSdpAttrIdOffsetServiceName,
KServiceName);
// Add a description to the record,描述
iSdpDatabase.UpdateAttributeL(iRecord,
KSdpAttrIdBasePrimaryLanguage +
KSdpAttrIdOffsetServiceDescription,
KServiceName);
iSdpDatabase.Close();
sdp.Close();
return 0 ;
}
// 这里设置蓝牙SDP服务中的协议相关信息
void CBtSvr::BuildProtocolDescriptionL(CSdpAttrValueDES * aProtocolDescriptor, TInt aPort)
{
TBuf8 < 1 > channel;
channel.Append((TChar)aPort);
aProtocolDescriptor
-> StartListL()
-> BuildDESL()
-> StartListL() // Details of lowest level protocol
// L2CAP层之上
-> BuildUUIDL(KL2CAP)
-> EndListL()
-> BuildDESL()
-> StartListL()
-> BuildUUIDL(KRFCOMM)
// 这里是绑定的RFCOMM的端口号
-> BuildUintL(channel)
-> EndListL()
-> EndListL();
}
int CBtSvr::BuildSerivce( const TDesC & ServiceName, TInt KSerialClassID)
{
TBTSockAddr add;
int ret;
_LIT(KRFCOMM, " RFCOMM " );
// connect to server
if (sockSvr.Connect() != KErrNone) {
return - 1 ;
}
// Open a socket
if (listenSock.Open(sockSvr, KRFCOMM) != KErrNone) { // ERR_OPEN
ret = - 1 ;
goto ERR_CONN;
}
// 得到一个可用的RFCOMM端口号
listenSock.GetOpt(KRFCOMMGetAvailableServerChannel, KSolBtRFCOMM, channelNum);
add.SetPort(channelNum);
if (listenSock.Bind(add) != KErrNone) {
ret = - 1 ;
goto ERR_OPEN;
}
else {
// 设置安全信息
TRAPD(err, (SetSecurityOnChannelL(EFalse, EFalse, ETrue, channelNum)));
if (err != KErrNone) {
ret = - 1 ;
goto ERR_OPEN;
}
// 注册SDP服务
TRAP(err, (RegieterBlueToothServerL(ServiceName, KSerialClassID)));
if (err != KErrNone) {
ret = - 1 ;
goto ERR_OPEN;
}
return 0 ;
}
ERR_OPEN:
listenSock.Close();
ERR_CONN:
sockSvr.Close();
return ret;
}
现在再派生出一个子类BtDbg,实现send功能
class
BtDbg :
public
CBtSvr
{
public :
~ BtDbg();
static BtDbg * NewLC();
static BtDbg * NewL();
void ConstructL();
int Send( const TDesC8 & aDesc);
friend int BtDbg_printf( const char * format, ...);
private :
int BindL( void );
};
BtDbg * BtDbg::NewLC()
{
BtDbg * result = new (ELeave) BtDbg();
CleanupStack::PushL( result );
result -> ConstructL();
return result;
}
BtDbg * BtDbg::NewL()
{
BtDbg * result = BtDbg::NewLC();
CleanupStack::Pop( result );
return result;
}
void BtDbg::ConstructL()
{
}
BtDbg:: ~ BtDbg()
{
}
int BtDbg::BindL( void )
{
_LIT(ServiceName, " Debug " );
return BuildSerivce(ServiceName, 0x1101 );
}
int BtDbg::Send( const TDesC8 & aDesc)
{
if (iStat != EInConnection) {
return - 1 ;
}
// 同步的发送数据
connSock.Write(aDesc, iSendStatus);
User::WaitForRequest(iSendStatus);
if (iSendStatus != KErrNone) {
return - 1 ;
}
return 0 ;
}
{
public :
~ BtDbg();
static BtDbg * NewLC();
static BtDbg * NewL();
void ConstructL();
int Send( const TDesC8 & aDesc);
friend int BtDbg_printf( const char * format, ...);
private :
int BindL( void );
};
BtDbg * BtDbg::NewLC()
{
BtDbg * result = new (ELeave) BtDbg();
CleanupStack::PushL( result );
result -> ConstructL();
return result;
}
BtDbg * BtDbg::NewL()
{
BtDbg * result = BtDbg::NewLC();
CleanupStack::Pop( result );
return result;
}
void BtDbg::ConstructL()
{
}
BtDbg:: ~ BtDbg()
{
}
int BtDbg::BindL( void )
{
_LIT(ServiceName, " Debug " );
return BuildSerivce(ServiceName, 0x1101 );
}
int BtDbg::Send( const TDesC8 & aDesc)
{
if (iStat != EInConnection) {
return - 1 ;
}
// 同步的发送数据
connSock.Write(aDesc, iSendStatus);
User::WaitForRequest(iSendStatus);
if (iSendStatus != KErrNone) {
return - 1 ;
}
return 0 ;
}
下面代码中的btDbg是事先实例化好的一个BtDbg对象。
static
char
rxBuf[
1024
*
10
];
int BtDbg_printf( const char * format, ...)
{
va_list ap;
int len = 0 ;
va_start(ap, format);
vsprintf(( char * )rxBuf, format, ap);
va_end(ap);
TPtrC8 pBuf = TPtrC8::TPtrC8((unsigned char * )rxBuf);
if (btDbg && btDbg -> Status() == CBtSvr::EInConnection) {
len = btDbg -> Send(pBuf);
}
return len;
}
int BtDbg_printf( const char * format, ...)
{
va_list ap;
int len = 0 ;
va_start(ap, format);
vsprintf(( char * )rxBuf, format, ap);
va_end(ap);
TPtrC8 pBuf = TPtrC8::TPtrC8((unsigned char * )rxBuf);
if (btDbg && btDbg -> Status() == CBtSvr::EInConnection) {
len = btDbg -> Send(pBuf);
}
return len;
}