📄 bluetooth1.cpp
字号:
//
// BlueTooth1.cpp - BlueTooth1 example
//
// Copyright (C) UIQ Technology AB, 2007
//
// This material is provided "as is" without any warranty to its performance or functionality.
// In no event shall UIQ Technology be liable for any damages whatsoever arising out of the
// use or inabilty to use this material.
//
#include "BlueTooth1.h"
#include "BlueTooth1.hrh"
#include <BlueTooth1.rsg>
#include <QikViewBase.h>
#include <QikCommand.h>
#include <QikListBoxModel.h>
#include <QikListBox.h>
#include <MQikListBoxData.h>
#include <eikstart.h>
#include <es_sock.h>
#include <bt_sock.h>
#include <btsdp.h>
#include <BtManClient.h>
#include <BTExtNotifiers.h>
#include <QBtSelectDlg.h> // for UIQ Bt target selection
//////////////////////////////////////////////////////////////////////////////
// The application Uid here MUST match UID3 defined in the MMP file
// This is a development UID and must NOT be used in production type software
const TUid KAppSpecificUid={0xEDEAD012};
// internal secondary view id, must be unique amongst this applications views
const TUid KUidListView={0x00000001};
// views within applications are fully identified by the app Uid and secondary view id
#define KViewIdListView TVwsViewId(KAppSpecificUid,KUidListView)
//////////////////////////////////////////////////////////////////////////////////
// Simple support for a variable number of log text to be displayed by a ui.
class CLogText : public CBase
{
public:
// new methods
~CLogText();
void ConstructL();
TInt Count();
const TDesC& At(const TInt aIndex);
void LogText(const TDesC& aBuf);
void ResetText();
protected:
CArrayFixFlat<HBufC*>* iText;
};
CLogText::~CLogText()
{
ResetText();
delete(iText);
}
void CLogText::ConstructL()
{
iText=new(ELeave)CArrayFixFlat<HBufC*>(32);
}
TInt CLogText::Count()
// Report number of logged messages
{
return(iText->Count());
}
const TDesC& CLogText::At(const TInt aIndex)
// report 'n'th text message
{
return(*iText->At(aIndex));
}
void CLogText::ResetText()
// Reset list of text items to contain 0 elements
{
TInt count=Count();
for (TInt i=0;i<count;i++)
delete(iText->At(i));
iText->Reset();
}
void CLogText::LogText(const TDesC& aBuf)
// add new text item to front of the list
{
TRAPD(err,
// truncate if required, UI cant display this width anyway...
TBuf<128>bb;
if (aBuf.Length()>120)
bb=aBuf.Left(120);
else
bb=aBuf;
HBufC* q=bb.AllocLC();
iText->InsertL(0,q); // at front of list
CleanupStack::Pop(q);
if (iText->Count()>100)
{ // restrict to last 100 log msgs
delete(iText->At(100)); // delete the content
iText->Delete(100); // remove index entry
}
);
}
//////////////////////////////////////////////////////////////////////////////////
enum TBluetoothStatus
{
EBtsConnectionEstablished, // a connection has been established
EBtsDisconnected, // connection been disconnected
EBtsDataTransmitted, // data has been transmitted
};
class MBtEngineObserver
{
public:
virtual void LogInfo(const TDesC& aBuf)=0;
virtual void StatusInfo(const TBluetoothStatus aStatus,const TInt aVal)=0;
virtual void DataReceived(const TDesC8& aData)=0;
};
/////////////////////////////////////////////////////////////////////////////////////////////////
// Obj responsible for writing data to a remotely connected BT entity
const TInt KSerialPortServiceClass = 0x1101; // a magic BT spec number
// in our app all data transferred contains these 5 bytes of data preceding the actual content.
// Its an abbreviations for 'Example Application Header' so we have confidence in what we are receiving
// is what we are expecting.
_LIT8(KBluetoothHeaderText,"ExHdr");
const TInt KMaxBluetoothHeaderSize=6; // ExHdr<len>
const TInt KMaxBluetoothDataSize=128; // max of 128 bytes of user data
const TInt KMaxBluetoothFrameSize=KMaxBluetoothDataSize+KMaxBluetoothHeaderSize;
class CBtWriter : public CActive
{
protected:
// from CActive
void DoCancel();
void RunL();
public:
// ew methods
~CBtWriter();
CBtWriter(RSocket& aSocket,MBtEngineObserver* aObserver);
TBool SendData(const TDesC8& aData);
protected:
RSocket& iSocket;
MBtEngineObserver* iObserver;
TBuf8<KMaxBluetoothFrameSize> iData;
};
CBtWriter::CBtWriter(RSocket& aSocket,MBtEngineObserver* aObserver) :
CActive(CActive::EPriorityLow),iSocket(aSocket),iObserver(aObserver)
{
CActiveScheduler::Add(this);
}
CBtWriter::~CBtWriter()
{
Cancel(); // calls DoCancel() iff we are currently active.
}
TBool CBtWriter::SendData(const TDesC8& aData)
// Were requested to send this data. If were currently active report that we cannot send the
// data at this time, dont take ownership of the data. Otherwise take copy of the data and
// start sending it.
{
// the last SendData() request has not yet finished.
if (IsActive())
return(EFalse);
iData=KBluetoothHeaderText; // fixed hdr of ExHdr<len>
iData.Append(aData.Length()); // a single byte because KMaxBluetoothDataSize is 128
iData.Append(aData);
// start transmission of data. It will have finished when our RunL() gets called
iSocket.Write(iData,iStatus);
// dont forget to mark the AO as representing an outstanding event
SetActive();
// we started data transmission.
return(ETrue);
}
void CBtWriter::RunL()
// Weve finished writing, sucessfully or otherwise.
{
iObserver->StatusInfo(EBtsDataTransmitted,iStatus.Int());
}
void CBtWriter::DoCancel()
// Cancel any outstanding activity, maybe called from destructor
// To get here we must have an outstanding Write() request.
{
iSocket.CancelWrite();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Connection initiators or acceptors derived from here
class CBtConnection : public CActive
{
protected:
enum TBtReadingStates
{
EReadingHeader, // currently reading the Frame header
EReadingContent, // reading the frame body
};
// new methods
void Panic(const TInt aReason) const;
void Read();
void ReadContent();
void RequestComplete(const TInt aErr);
public:
// new methods
CBtConnection(RSocketServ& aServ,MBtEngineObserver* aOwner);
virtual TBool SendData(const TDesC8& aData)=0;
protected:
RSocketServ& iSocketServer;
MBtEngineObserver* iObserver; // who to report things to
RSocket iSocket; // for reading/writing data over
TBtReadingStates iReadingState; // whether were reading headr or body
TBuf8<KMaxBluetoothHeaderSize> iFrameHdr; // read hdr here into here
TPtr8 iDataPtr;
TBuf8<KMaxBluetoothFrameSize> iData; // read data into here/write data from here
};
void CBtConnection::Panic(const TInt aReason) const
{
_LIT(KBtConnection,"CBtConnection");
User::Panic(KBtConnection,aReason);
}
void CBtConnection::Read()
// Start a read of data request
{
__ASSERT_DEBUG(!IsActive(),Panic(0));
// in our app all frames we can reasonably process must have at least our frame Hdr on them we can
// read until we see the entire hdr.
iSocket.Recv(iFrameHdr,0,iStatus); // iFrameHdr is KMaxBtDriverFrameHdr bytes long
// this AO now represents an outstanding event
SetActive();
// and we are reading the frame header
iReadingState=EReadingHeader;
}
void CBtConnection::ReadContent()
// Start a read of data content
{
__ASSERT_DEBUG(!IsActive(),Panic(1));
// read amount weve been told is in next frame, into the iData buffer.
// iFrameHdr[] must contain ExHdr<len> to get here so [5] contains the length for this app.
// This app only supports a max of 128 bytes per frame...
iDataPtr.Set((TUint8*)iData.Ptr(),0,iFrameHdr[5]);
// we can read the entire content in a single read
iSocket.Recv(iDataPtr,0,iStatus);
// this AO now represents an outstanding event
SetActive();
// and we are reading the frame content
iReadingState=EReadingContent;
}
void CBtConnection::RequestComplete(const TInt aErr)
// Report completion via the active object
{
TRequestStatus* q=(&iStatus);
User::RequestComplete(q,aErr); // post error though active object
}
CBtConnection::CBtConnection(RSocketServ& aServ,MBtEngineObserver* aOwner) :
CActive(CActive::EPriorityLow),iSocketServer(aServ),iObserver(aOwner),iDataPtr(NULL,0,0)
{
CActiveScheduler::Add(this);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// This part of the engine listens for incoming BT requests and accepts connections.
class CBtConnectionListener : public CBtConnection
{
protected:
enum TBtListenerStates
{
EListenerStateIdle, // idle, nothing much going on (val of 0 = default state on Contruct)
EListenerStateConnecting, // attempting connection establihment
EListenerStateConnected, // socket connected + read queued
};
// from CActive
void DoCancel();
void RunL();
// new methods
void SetAvailability(const TInt aAvailabilityState);
void StopAdvertising();
public:
// from CBtConnection
TBool SendData(const TDesC8& aData);
// new methods
~CBtConnectionListener();
CBtConnectionListener(RSocketServ& aServ,MBtEngineObserver* aOwner);
void ConstructL();
void StartListening();
TInt IsConnected() const;
protected:
RSocket iListener; // for connection establishment
CBtWriter* iWriteChannel; // who writes data on our behalf
// Service discovery database interface handling
RSdp iSdp; // Service discovery server
RSdpDatabase iSdpDatabase; // db handle
TSdpServRecordHandle iRecordHandle; // our service within the db
TInt iServiceRecordState; // so we can mark the service as changed
TBtListenerStates iState; // what our state machine is currently doing
};
CBtConnectionListener::CBtConnectionListener(RSocketServ& aServ,MBtEngineObserver* aOwner) :
CBtConnection(aServ,aOwner)
{}
CBtConnectionListener::~CBtConnectionListener()
{
StopAdvertising(); // only does anything if started advertising - thus Db was opened etc
iSdpDatabase.Close();
iSdp.Close();
// cancel any outstanding connect/read requests
Cancel();
// before we close the socket - cancel any outstanding write request
delete(iWriteChannel);
// now all async requests been cancelled we can sensibly close the socket we xfer data over.
iSocket.Close();
// now shut down the socket we listend for incoming connection requests on
iListener.Close();
}
void CBtConnectionListener::ConstructL()
// Open an incoming connection request listener, create the socket that the incoming connection
// will be contained within.
{
// any write requests are handled by this active object
iWriteChannel=new(ELeave)CBtWriter(iSocket,iObserver);
// obtain an IPC connection to the socket server
User::LeaveIfError(iListener.Open(iSocketServer,KRFCOMMDesC));
// request a free BT port
TInt port;
User::LeaveIfError(iListener.GetOpt(KRFCOMMGetAvailableServerChannel,KSolBtRFCOMM,port));
TBTSockAddr addr;
addr.SetPort(port);
// setup the security settings for a point to point BT connection
TBTServiceSecurity serviceSecurity;
serviceSecurity.SetUid(KUidServiceSDP);
serviceSecurity.SetAuthentication(EFalse);
serviceSecurity.SetEncryption(EFalse);
serviceSecurity.SetAuthorisation(ETrue);
serviceSecurity.SetDenied(EFalse);
addr.SetSecurity(serviceSecurity);
// now reqest we start listening on the indicated port for connection requests
User::LeaveIfError(iListener.Bind(addr));
User::LeaveIfError(iListener.Listen(1));
// connect to the service discovery subsystem
User::LeaveIfError(iSdp.Connect());
User::LeaveIfError(iSdpDatabase.Open(iSdp));
// we want a serial port service
iSdpDatabase.CreateServiceRecordL(KSerialPortServiceClass,iRecordHandle);
// with the following protocol description
// this needs to match the lSerialPortAttributeList[] structure - as thats what were going to parse against
CSdpAttrValueDES* sdpAttr=CSdpAttrValueDES::NewDESL(NULL);
CleanupStack::PushL(sdpAttr);
TBuf8<1> bb8;
bb8.Append(port); // the remote will extract this info to know what port to connect to
sdpAttr
->StartListL()
->BuildDESL()
->StartListL()
->BuildUUIDL(KL2CAP)
->EndListL()
->BuildDESL()
->StartListL()
->BuildUUIDL(KRFCOMM)
->BuildUintL(bb8)
->EndListL()
->EndListL();
// and add that to the SDP database record
iSdpDatabase.UpdateAttributeL(iRecordHandle,KSdpAttrIdProtocolDescriptorList,*sdpAttr);
CleanupStack::PopAndDestroy(sdpAttr);
// add short human readable name for the service, dont support anything other than English
_LIT(KUiqBtExample,"UiqBtExample");
iSdpDatabase.UpdateAttributeL(iRecordHandle,
KSdpAttrIdBasePrimaryLanguage+KSdpAttrIdOffsetServiceName,KUiqBtExample);
// add human readable description for the service
_LIT(KUIQBookExampleBlueToothservice,"UIQ, Book Example, BlueTooth service");
iSdpDatabase.UpdateAttributeL(iRecordHandle,
KSdpAttrIdBasePrimaryLanguage+KSdpAttrIdOffsetServiceDescription,KUIQBookExampleBlueToothservice);
}
void CBtConnectionListener::SetAvailability(
// Set the availability of this service for a remote enquiry entity
const TInt aAvailabilityState) // 0xFF for unused, 0x00 for used
{
if (iRecordHandle!=0)
{
TRAPD(junk,
iSdpDatabase.UpdateAttributeL(iRecordHandle,KSdpAttrIdServiceAvailability,aAvailabilityState);
iServiceRecordState++; // Mark the record as changed by updating state number
iSdpDatabase.UpdateAttributeL(iRecordHandle,KSdpAttrIdServiceRecordState,iServiceRecordState);
);
}
}
void CBtConnectionListener::StopAdvertising()
// Stop advertising our service - if we were advertising it in first place
{
if (iRecordHandle!=0)
{ // we started advertising
TRAPD(junk,iSdpDatabase.DeleteRecordL(iRecordHandle));
iRecordHandle=0;
}
}
void CBtConnectionListener::StartListening()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -