📄 bluetooth1.cpp
字号:
// Start the acceptance of a connection from a remote BT entity
// In all cases we exit from here will an event source outstanding.
{
__ASSERT_DEBUG(iState==EListenerStateIdle,Panic(2));
TInt ret=iSocket.Open(iSocketServer);
if (ret==KErrNone)
{
SetAvailability(0xFF); // publish our service as available now fully set up + listening
iListener.Accept(iSocket,iStatus);
}
else
RequestComplete(ret); // defer dealing with errors until the RunL()
SetActive();
iState=EListenerStateConnecting;
_LIT(KListening,"Listening");
iObserver->LogInfo(KListening);
}
TBool CBtConnectionListener::SendData(const TDesC8& aData)
// We use the iWriteChannel for writing - so simply route to that. Our AO is used
// for read completions.
{
if (iState!=EListenerStateConnected)
return(EFalse); // block writes cos were connecting/shutting down at this precise moment
return(iWriteChannel->SendData(aData));
}
void CBtConnectionListener::DoCancel()
// Cancel any outstanding activity, maybe called from destructor - if so the listbox has disappeared by
// here so cant log any messages.
{
switch (iState)
{
case EListenerStateConnecting: // we were attempting to accept the connection
iListener.CancelAccept();
break;
case EListenerStateConnected:
iSocket.CancelRead();
break;
default:
Panic(3); // what AO is running ?
break;
}
iState=EListenerStateIdle;
}
void CBtConnectionListener::RunL()
// A socket event has occured.
{
switch (iState)
{
case EListenerStateConnected: // data arrived for us to process
if (iReadingState==EReadingHeader)
{
TInt error=iStatus.Int();
if (error==KErrNone)
{ // weve got the hdr, ensure its correct content, if so get main body
TPtr8 q((TUint8*)iFrameHdr.Ptr(),5,5);
if (q==KBluetoothHeaderText)
{
ReadContent(); // get the frame proper
break;
}
// header is broken, were out of sync or communicating with the wrong thing...
// shut down and re-start
error=KErrCorrupt;
}
iObserver->StatusInfo(EBtsDisconnected,error);
iState=EListenerStateIdle;
iSocket.Close();
StartListening(); // re-try connection
}
else
{ // process whole frame
if (iStatus.Int()==KErrNone)
{
iData.SetLength(iDataPtr.Length());
iObserver->DataReceived(iData);
Read(); // get next frame header, DataReceived() sorts out errors b4 here
}
else
{
iObserver->StatusInfo(EBtsDisconnected,iStatus.Int());
iState=EListenerStateIdle;
iSocket.Close();
StartListening(); // re-try connection
}
}
break;
case EListenerStateConnecting: // weve finished connect request
SetAvailability(0x00); // no more connections at this time
if (iStatus.Int()==KErrNone)
{
iState=EListenerStateConnected;
Read();
iObserver->StatusInfo(EBtsConnectionEstablished,KErrNone);
}
else
{ // shutdown and start again
_LIT(KListenError,"Listen Error");
iObserver->LogInfo(KListenError);
iState=EListenerStateIdle;
iSocket.Close();
StartListening(); // re-try connection
}
break;
default:
Panic(4); // what AO is running ?
break;
}
}
TInt CBtConnectionListener::IsConnected() const
// Report if the connection creator is connected
{
return(iState==EListenerStateConnected);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// This part of the engine creates BT connections.
enum TAttributeAction
{
EAttrItemCheckType,
EAttrItemCheckTypeAndValue,
EAttrItemCheckEnd,
EAttrItemReadValue,
EAttrItemFinished
};
typedef struct {
TAttributeAction iAction; // what to do when encountering this item
TSdpElementType iElementType; // what were expecting the item to be
TInt iValue; // what val is associated with the ElementType
} SSdpAttributeItem;
static const SSdpAttributeItem lSerialPortAttributeList[] =
{
{EAttrItemCheckType,ETypeDES,0}, // validate we see a ETypeDES
{EAttrItemCheckType,ETypeDES,0}, // validate we see a ETypeDES
{EAttrItemCheckTypeAndValue,ETypeUUID,KL2CAP}, // ensure its a UUID for KL2CAP
{EAttrItemCheckEnd,ETypeNil,0}, // ensure thats all the attrs at that node
{EAttrItemCheckType,ETypeDES,0}, // validate we see a ETypeDES
{EAttrItemCheckTypeAndValue,ETypeUUID,KRFCOMM}, // ensure its a UUID for KL2CAP
{EAttrItemReadValue,ETypeUint,1}, // 1 == field Key for 'the port', the Uint will be that actual port
{EAttrItemCheckEnd,ETypeNil,0}, // ensure thats all the attrs at that node
{EAttrItemCheckEnd,ETypeNil,0}, // ensure thats all the attrs at that node
{EAttrItemFinished,ETypeNil,0} // ensure weve finished reading that attribute set
};
class CBtConnectionCreator : public CBtConnection, public MSdpAgentNotifier, public MSdpAttributeValueVisitor
{
protected:
enum TBtCreatorStates
{
ECreatorStateIdle, // not doing much (val = 0 == default construct val)
ECreatorStateFindService,
ECreatorStateConnecting, // attempting socket level connection
ECreatorStateConnected, // connected + able to transfer data
};
// from CActive
void DoCancel();
void RunL();
// from MSdpAttributeValueVisitor
void VisitAttributeValueL(CSdpAttrValue &aValue,TSdpElementType aType);
void StartListL(CSdpAttrValueList &aList);
void EndListL();
// from MSdpAgentNotifier
void NextRecordRequestComplete(TInt aError,TSdpServRecordHandle aHandle,TInt aTotalRecordsCount);
void AttributeRequestResult(TSdpServRecordHandle aHandle,TSdpAttributeID aAttrID,CSdpAttrValue* aAttrValue);
void AttributeRequestComplete(TSdpServRecordHandle,TInt aError);
// new methods
void Connect();
void NextNodeL();
public:
// from CBtConnection
TBool SendData(const TDesC8& aData);
// new methods
~CBtConnectionCreator();
CBtConnectionCreator(RSocketServ& aServ,MBtEngineObserver* aOwner);
void ConstructL();
void StartDiscoveryL();
TInt IsConnected() const;
protected:
CBtWriter* iWriteChannel; // who writes data on our behalf
TInt iRemotePort; // the remote port we need to connect on
CSdpAgent* iSdpAgent; // connection to remte SDP database
CSdpSearchPattern* iSdpSearchPattern; // what can search remote SDP database records
TInt iNodeIndex; // which node weve reached in parsing a remote SDP record
TInt iExtractedValue; // extracted whilst parsing the SDP record
TBTDevAddr iRemoteDevAddr;
TBTDeviceName iRemoteDevName;
TBTDeviceClass iRemoteDevClass;
TBtCreatorStates iState; // our state machine status
};
CBtConnectionCreator::CBtConnectionCreator(RSocketServ& aServ,MBtEngineObserver* aOwner) :
CBtConnection(aServ,aOwner)
{}
CBtConnectionCreator::~CBtConnectionCreator()
{
// 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();
}
void CBtConnectionCreator::ConstructL()
// Construct the Bt connection creator entities
{
User::LeaveIfError(iSocket.Open(iSocketServer,KRFCOMMDesC));
iWriteChannel=new(ELeave)CBtWriter(iSocket,iObserver);
}
void CBtConnectionCreator::Connect()
// Issue the connect request now we have the remote device address and port.
{
// setup the security settings for this app
TBTServiceSecurity serviceSecurity;
serviceSecurity.SetAuthentication(EFalse);
serviceSecurity.SetEncryption(EFalse);
serviceSecurity.SetAuthorisation(ETrue);
serviceSecurity.SetDenied(EFalse);
// setup which device ID and port to connect to
TBTSockAddr addr;
addr.SetBTAddr(iRemoteDevAddr);
addr.SetPort(iRemotePort); // as fetched from remote
addr.SetSecurity(serviceSecurity);
// and start the connection request
iSocket.Connect(addr,iStatus);
SetActive();
iState=ECreatorStateConnecting;
}
TBool CBtConnectionCreator::SendData(const TDesC8& aData)
// We use the iWriteChannel channel for writing - so simply route to that. Our AO is used
// for reading/connecting.
{
if (iState!=ECreatorStateConnected)
return(EFalse); // were not connected enough to allow writing of data
return(iWriteChannel->SendData(aData));
}
void CBtConnectionCreator::NextNodeL()
// Attempt to move to the next node. If weve already reached the end report this
{
if (lSerialPortAttributeList[iNodeIndex].iAction==EAttrItemFinished)
User::Leave(KErrEof);
iNodeIndex++;
}
void CBtConnectionCreator::VisitAttributeValueL(CSdpAttrValue &aValue,TSdpElementType aType)
// Called back by the CSdpAttrValue obj to allow us to parse + validate the contents
// are those we are searching for.
{
TBuf<32>bb;
_LIT(KVisitAttributeValueL,"VisitAttributeValueL %d");
bb.Format(KVisitAttributeValueL,iNodeIndex);
iObserver->LogInfo(bb);
switch (lSerialPortAttributeList[iNodeIndex].iAction)
{
case EAttrItemCheckType: // just check the type is as expected
if (lSerialPortAttributeList[iNodeIndex].iElementType!=aType)
User::Leave(KErrGeneral);
break;
case EAttrItemCheckTypeAndValue: // check type and values are as expected
if (lSerialPortAttributeList[iNodeIndex].iElementType!=aType)
User::Leave(KErrGeneral);
// check value is as expected
switch (aValue.Type())
{
case ETypeUint:
if (aValue.Uint()!=(TUint)lSerialPortAttributeList[iNodeIndex].iValue)
User::Leave(KErrArgument);
break;
case ETypeInt:
if (aValue.Int()!=lSerialPortAttributeList[iNodeIndex].iValue)
User::Leave(KErrArgument);
break;
case ETypeBoolean:
if (aValue.Bool()!=lSerialPortAttributeList[iNodeIndex].iValue)
User::Leave(KErrArgument);
break;
case ETypeUUID:
if (aValue.UUID()!=TUUID(lSerialPortAttributeList[iNodeIndex].iValue))
User::Leave(KErrArgument);
break;
default: // either not supported or bad
break;
}
break;
case EAttrItemCheckEnd:
case EAttrItemFinished: // too many items in list
User::Leave(KErrGeneral);
break;
case EAttrItemReadValue: // check type is as expected and read remote value
if (lSerialPortAttributeList[iNodeIndex].iElementType!=aType)
User::Leave(KErrGeneral);
iExtractedValue=aValue.Uint(); // possibly found the remote port info
// report some info
_LIT(KEAttrItemReadValue,"EAttrItemReadValue: %d");
bb.Format(KEAttrItemReadValue,iExtractedValue);
iObserver->LogInfo(bb);
break;
default:
break;
}
NextNodeL();
}
void CBtConnectionCreator::StartListL(CSdpAttrValueList& aList)
{
}
void CBtConnectionCreator::EndListL()
{
if (lSerialPortAttributeList[iNodeIndex].iAction!=EAttrItemCheckEnd)
User::Leave(KErrGeneral);
NextNodeL();
}
void CBtConnectionCreator::NextRecordRequestComplete(
// Called back by the iSdpAgent as its found a next record
TInt aError,
TSdpServRecordHandle aHandle,
TInt aTotalRecordsCount)
{
if (aError==KErrEof) // scanned all records - see if found the data were looking for
{
TBuf<32>bb;
_LIT(KErrEof,"KErrEof %d");
bb.Format(KErrEof,iRemotePort);
iObserver->LogInfo(bb);
RequestComplete(iRemotePort==(-1)?KErrNotFound:KErrNone);
}
else if (aTotalRecordsCount==0)
RequestComplete(KErrNotFound);
else if (aError!=KErrNone)
RequestComplete(aError);
else
{ // we want attributes of the record
TRAPD(err,iSdpAgent->AttributeRequestL(aHandle,KSdpAttrIdProtocolDescriptorList));
if (err!=KErrNone)
RequestComplete(err);
}
}
void CBtConnectionCreator::AttributeRequestResult(
// Called back by the iSdpAgent as its found answer to the AttributeRequestL()
TSdpServRecordHandle aHandle,
TSdpAttributeID aAttrID,
CSdpAttrValue* aAttrValue)
{
iNodeIndex=0; // scan that set of attribute/values from the start
TRAPD(err,aAttrValue->AcceptVisitorL(*this));
if (err!=KErrNone)
RequestComplete(err); // couldnt run AcceptVisitorL()
else if (lSerialPortAttributeList[iNodeIndex].iAction==EAttrItemFinished)
{
iRemotePort=iExtractedValue; // reached end of struct + all as expected - so this is the port
TBuf<32>bb;
_LIT(KPortIndex,"Port %d, Index %d");
bb.Format(KPortIndex,iRemotePort,iNodeIndex);
iObserver->LogInfo(bb);
}
}
void CBtConnectionCreator::AttributeRequestComplete(TSdpServRecordHandle aHandle,TInt aError)
// Called back by the iSdpAgent when weve finished processing the SDP record in AttributeRequestResult()
{
if (aError==KErrNone)
{
TRAP(aError,iSdpAgent->NextRecordRequestL()); // get next SDP record + see if its got our info
}
// deal with errors via 'completion' of the outstanding request
if (aError!=KErrNone)
RequestComplete(aError);
}
void CBtConnectionCreator::RunL()
// Something has happened, see what state were in + thus whats happened
{
switch (iState)
{
case ECreatorStateFindService:
// weve finished with these components
delete(iSdpAgent);
iSdpAgent=NULL;
delete(iSdpSearchPattern);
iSdpSearchPattern=NULL;
if (iStatus.Int()==KErrNone)
{ // weve sucessfully discovered the remote port
__ASSERT_DEBUG(iRemotePort!=(-1),Panic(0));
Connect();
}
else
{ // report we failed to connect
iObserver->StatusInfo(EBtsConnectionEstablished,iStatus.Int());
iState=ECreatorStateIdle;
}
break;
case ECreatorStateConnecting:
if (iStatus.Int()==KErrNone)
{ // sucessfully connected to remote, can now send/recv data
iState=ECreatorStateConnected;
Read(); // get any data thats sent to us
iObserver->StatusInfo(EBtsConnectionEstablished,KErrNone);
}
else
{ // failed to connect
iObserver->StatusInfo(EBtsConnectionEstablished,iStatus.Int());
iState=ECreatorStateIdle;
}
break;
case ECreatorStateConnected: // data arrived for us to process
if (iReadingState==EReadingHeader)
{
TInt error=iStatus.Int();
if (error==KErrNone)
{ // weve got the hdr, ensure its correct content, if so get main body
TPtr8 q((TUint8*)iFrameHdr.Ptr(),5,5);
if (q==KBluetoothHeaderText)
{
ReadContent(); // get the frame proper
break;
}
error=KErrCorrupt;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -