⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bluetooth1.cpp

📁 《UIQ 3 The Complete Guide》书的源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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 + -