You Are Here:

Community: Developer Discussion Boards

#1 Old Thumbs up Some useful issues about bluetooth (at least for C++) - 2008-11-27, 13:00

Join Date: Jun 2008
Posts: 17
Andrey.Tetyuev
Offline
Registered User
Hi All,

I hope - that text helps somebody during research of BT problems.
In our application it was required to establish SPP connection over BT (with GPS receiver or Car-Kit which also sends GPS data). Parallel the phone uses the A2DP or the HFP to pass the Audio to the Car-Kit.

Here is description of some problems and solutions (works at S60, tested with N95).

1) If you call the Notifier to get the BT Power "On", and the BT Power was already "On" - the existing audio BT connection will be broken (so if you already have the audio connection before that notifier call - it will be stopped from Symbian).
Solution: check if the BT is off before call that notifier:

Code:
TInt MyClass::GetCurrentPowerState()
{
    CRepository *crep = CRepository::NewL(KCRUidBluetoothPowerState);
    TInt value=0;
    CleanupStack::PushL( crep );
    User::LeaveIfError( crep->Get(KBTPowerState, value) );
    CleanupStack::PopAndDestroy( crep );
    return value;
}

if (EBTPowerOn == GetCurrentPowerState())
{
    // the BT is already "on", just do what you like to do
}
else
{
    User::LeaveIfError(MyRNotifier.Connect());
    MyRNotifier.StartNotifierAndGetResponse(
                    iStatus,
                    KPowerModeSettingNotifierUid,
                    m_pckg,
                    m_result);
    SetActive();
}
2) If you call "connect" for the RSocket to the BT device (given by Address and Port), which is not more present (i.e. turned off) - the existing audio connection will be broken.
Solution: try to discover the services at the target BT-device before connect to it (You don't need to discover the devices, just discover the services for known address).
Note: discovering the services at BT devices (so far as discovering of BT devices) "loads" the BT - so the audio transmition (sound) will be interrupted, but will stay "alive" (so the audio connection will not be broken). To avoid a high loading of audio connection through services discovering - add an adaptive timeout between trying to reconnect. For example - initially try to reconnect 3 times with delay = 5 seconds between reconnections, then try to connect each 40 seconds. So far the connection was established - you can reset the counter of timeouts.
I'm talking here about connection to the already known device (i.e. to address which is already saved in your program configuration as "last used"). In case you just connect to the device which was discovered right now (i.e. which was selected by user from corresponding dialog) - you don't need such complex behaviour, just connect to it.

If the device is here - the discovering of first SPP service goes really fast (less that 2 seconds), so you can use it before each connection. In case the device is not present - it takes longer, so you need a timeout to abort the discovering (for example - 5 seconds).

Hope, that helps for somebody.

Good Luck!
Andrey
Reply With Quote

#2 Old Thumbs up Re: Some useful issues about bluetooth (at least for C++) - 2008-11-27, 13:01

Join Date: Jun 2008
Posts: 17
Andrey.Tetyuev
Offline
Registered User
P.S. here is the example of checker - if the device is still here (i.e. Discover of SPP services):

// Header

Code:
#ifndef CBTDeviceDiscover_h
#define CBTDeviceDiscover_h 1

// required capabilities: LocalServices
// used libraries: sdpagent.lib, sdpdatabase.lib

#include <btsdp.h>


// determines template for callback class/function which is used by CBTDeviceDiscover so far it gets result
class CBTDeviceDiscover_CallBack
{
    public:
        // callback function declaration to be implemented in your class; bDevicePresent=true if the device was found;
        virtual void BTDeviceDiscovered( bool bDevicePresent, TUint uiPort, bool bPortValid ) = 0;
};


// class CBTDeviceDiscover used to check if the BT device with given address is still present (by discovering the services of device)
class CBTDeviceDiscover : public CBase,
                          public MSdpAgentNotifier,
                          public MSdpAttributeValueVisitor
{
    public:
        
        // constructor
        CBTDeviceDiscover(CBTDeviceDiscover_CallBack & rCallBackClass);
        
        // destructor
        ~CBTDeviceDiscover();
        
        // discover if the device with given address present (asynchronous).
        void DiscoverDeviceL(TBTDevAddr & devAddr);
        
        // stopes the discovery (aborts it and delete variables used for it) 
        void StopDiscovery();

    private:
        
        // from MSdpAgentNotifier:
        void NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount);
        void AttributeRequestResult(TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue);
        void AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError);
                
        // from MSdpAttributeValueVisitor:
        void VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType); // Called for processing of each service attribute.
        void StartListL(CSdpAttrValueList &aList); // should be declared, but not needed to be implemented
        void EndListL(); // should be declared, but not needed to be implemented
                
        // member variables:
        
        CBTDeviceDiscover_CallBack & m_rCallBackClass; // reference to callback class used if the discovery is finished
        TBTDevAddr m_devAddr; // BT device address
        CSdpAgent * m_pAgent; // Service discovery agent
        CSdpSearchPattern * m_pSearchPattern; // Service discovery search pattern
        TUUID m_uiCurrUUID; // currently discovered attribute uuid in the service attributes
        TUint m_uiPort; // Port (comm channel) found in the service attributes
        bool m_bPortValid; // true if the Port was retrieved
        bool m_bDiscovering; // true if currently discovering the device (if interested on results of listener functions) 
};

#endif // #ifndef CBTDeviceDiscover_h
// Source file:

Code:
#include <bt_sock.h>
// don't forget to adapt to your paths
#include "CBTDeviceDiscover.h"


CBTDeviceDiscover::CBTDeviceDiscover(CBTDeviceDiscover_CallBack & rCallBackClass)
    : m_rCallBackClass(rCallBackClass),
      m_pAgent(NULL),
      m_pSearchPattern(NULL),
      m_uiCurrUUID(0),
      m_uiPort(0),
      m_bPortValid(FALSE),
      m_bDiscovering(FALSE)
{
    m_devAddr.Reset();
}

CBTDeviceDiscover::~CBTDeviceDiscover()
{
    StopDiscovery();
}

void CBTDeviceDiscover::DiscoverDeviceL(TBTDevAddr & devAddr)
{   
    StopDiscovery(); // to avoid conflicts if called several times before the old discovery is finished
    
    const TInt BT_UUID_SPP_SP = 0x1101; // SPP (Serial Port) UUID
    m_devAddr = devAddr;
    
    // Init new service discovery agent
    m_pAgent = CSdpAgent::NewL( *this, m_devAddr );
    
    // Set search properties for agent (use SPP service-UUID to filter the services discovered)
    m_pSearchPattern = CSdpSearchPattern::NewL();
    m_pSearchPattern->AddL(BT_UUID_SPP_SP);
    m_pAgent->SetRecordFilterL(*m_pSearchPattern);
    
    m_bDiscovering = TRUE;
    // Initiate search, result will be received with call of NextRecordRequestComplete()
    m_pAgent->NextRecordRequestL();
}

void CBTDeviceDiscover::StopDiscovery()
{
    m_bDiscovering = FALSE;
    if(m_pAgent)
    {
        m_pAgent->Cancel();
        delete m_pAgent;
        m_pAgent = NULL;
    }
    if(m_pSearchPattern)
    {
        m_pSearchPattern->Reset();
        delete m_pSearchPattern;
        m_pSearchPattern = NULL;
    }
    m_bPortValid = FALSE;
    m_uiPort = 0; // the BT port is unknown
}

// called when the service discovery agent has completed discovering services on device (i.e. if next service found or not)
void CBTDeviceDiscover::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount)
{
    if ( ( KErrNone==aError) && (0<aTotalRecordsCount) )
    {
        // We got next service record, request protocol descriptor to retrieve remote port
        // (it calls later the AttributeRequestResult() when the answer is ready)
        TRAPD(err,m_pAgent->AttributeRequestL(aHandle, KSdpAttrIdProtocolDescriptorList));
        if( err )
        {
            StopDiscovery();
            m_rCallBackClass.BTDeviceDiscovered(true, 0, false);
        }
    }
    else
    {
        // no any services found or error occures (probably the device is not present or SPP service is not present)
        StopDiscovery();
        m_rCallBackClass.BTDeviceDiscovered(false, 0, false);
    }
}

// Called when the service attributes for the service record have been retrieved.
void CBTDeviceDiscover::AttributeRequestResult(TSdpServRecordHandle, TSdpAttributeID,
        CSdpAttrValue* aAttrValue)
{
    // can't ignore the call of this function because we need take care about aAttrValue

    // Parse attributes, it will return results by several calls of VisitAttributeValue()
    TRAPD( err, aAttrValue->AcceptVisitorL(*this) );
    if( err )
    {
        StopDiscovery();
        m_rCallBackClass.BTDeviceDiscovered(true, 0, false);
    }
    delete aAttrValue;
}

// Called when the request to resolve the service attributes for the service record completes.
void CBTDeviceDiscover::AttributeRequestComplete(TSdpServRecordHandle, TInt aError)
{
    m_rCallBackClass.BTDeviceDiscovered(true, m_uiPort, m_bPortValid);
    // if KErrNone ==aError and we need not just the first SPP service but check several services,
    // can call for m_pAgent->NextRecordRequestL() here (and add corresponded processing in
    // NextRecordRequestComplete() )
    if (KErrNone != aError)
    {
        // Error processing (if required)
    }
    StopDiscovery();
}
    
// Called for processing of each service attribute.
void CBTDeviceDiscover::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType)
{
    if ( ! m_bDiscovering )
    {
        return; // ignore calls to that function if not discovering currently
    }
    
    // Check for attributes of UUID type. If the UUID is RFCOMM UUID, resolve the value for this attribute,
    // which will be the channel number.
    switch (aType)
    {
        case ETypeUUID: // UUID of attribute, store it 
        {
            TPtrC8 uuid(aValue.UUID().ShortestForm());
            m_uiCurrUUID.SetL(uuid);
            break;
        }
        case ETypeUint: // uint value, check if the current attribute type is KRFCOMM, store the port value if "yes"
        {
            if ( m_uiCurrUUID==KRFCOMM )
            {
                m_uiPort=aValue.Uint();
                m_bPortValid = TRUE;
                m_bDiscovering = FALSE;
            }
            break;
        }
        default:
            // other attributes are not interesting for processing...
            break;
    }
}

void CBTDeviceDiscover::StartListL(CSdpAttrValueList&)
{
}

void CBTDeviceDiscover::EndListL()
{
}
Reply With Quote
Reply « Previous Thread | Next Thread »
Display Modes
Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules

You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Forum Jump
Similar Threads
Thread Thread Starter Forum Replies Last Post
Bluesoleil Software kencooper Bluetooth Technology 9 2008-08-29 20:46
Bluelet - Rapid Bluetooth App Development (Free source) huiben Mobile Java General 4 2008-07-25 16:52
Bluetooth State satyadeepg Mobile Java Networking & Messaging & Security 2 2007-06-10 19:11
Bluetooth GPS simulator for j2me phone vgps Mobile Java Networking & Messaging & Security 2 2007-02-09 05:30
Bluetooth Emulation aohx075 Mobile Java Tools & SDKs 0 2004-08-24 05:14

Rate This

 
Bookmark this page: DeliciousDiggFacebookGoogleYahooStumbleUponRedditDiigoTechnocratiTwitter  Share this page Share this page Print this Page Print this page Invite a friend Invite a friend
京ICP备05048969号    Email Newsletters Press Terms & Conditions Privacy Policy Sitemap Contact Us © 2009 Nokia