Discussing the nuts and bolts of software development

Monday, April 30, 2007

 

Bluetooth Handsfree Profile Support for Windows Mobile 5 - The Series (Part 2)

Bluetooth HandsFree Profile Support for Windows Mobile 5 - part 2

In our last article, we explored some of the interfaces offered by the Audio Gateway (AG) for developers.
The problem was that some of the mechanisms offered in WinCE to signal the AG core of specific network events are not present in the PPC and Smartphone SDK. In this article, I'll show you how to create a lightweight replacement for the AG without spending two weeks (or more) figuring out what's inside that little "black box" they call the Audio Gateway. Please be aware I've never worked for Microsoft and everything within this article should be considered "as is".

To start, I'll give you some background information on how the AG core is constructed and then I'll share specific details on creating a connection with the Bluetooth device, processing AT commands, and routing audio to the Bluetooth chip.

The AG core consists of 3 modules:

Parser: Once the AG core has established a socket connection with the Bluetooth Headset device, the interactions between the WM5 device and the Bluetooth Headset are signed via the socket connection with AT Commands. The parser' responsibility is to retrieve these messages from the socket, parse them and return them to the Handler module for processing.

Interface: Exposes methods to signal the network states and initiate commands from the services layer. It also listens for incoming Bluetooth device requests that are trying to create a baseband connection, whether synchronously or asynchronously.

Handler: The core module that receives input from both the Interface module and the Parser module and, based on those stimuli and the internal state of the AG core, will respond accordingly, i.e. send AT command responses, create a service level socket connection, an IOCTL call to the audio driver to route voice...etc.

The Meat and Bones of the Parser
The parser is quite simple. After the Handler creates a socket connection with the Bluetooth Headset (I'll talk more about that in the third installment) it passes the connected socket to the Parser module to listen for and receive incoming AT commands. Listed below are the AT commands that are supported by the Bluetooth HandsFree profile and their corresponding general definitions.

"AT+CKPD=200" - Indicates a Bluetooth button press
"AT+VGM=" - Indicates a microphone volume change
"AT+VGS=" - Indicates a speakerphone volume change
"AT+BRSF=" - The Headset is asking what features are supported
"AT+CIND?" - The Headset is asking about the indicators that are signaled
"AT+CIND=?" - The Headset is asking about the test indicators
"AT+CMER=" - The Headset is asking which indicates are registered for updates
"ATA" - When an incoming call has been answered, usually a Bluetooth button press
"AT+CHUP" - When a call has been hung up, usually a Bluetooth button press
"ATD>" - The Headset is requesting the local device to perform a memory dial
"ATD" - The Headset is requesting to dial the number
"AT+BLDN" - The Headset is requesting to perform last number dialed
"AT+CCWA=" - The Headset has enabled call waiting
"AT+CLIP=" - The Headset has enabled CLI (Calling Line Identification)
"AT+VTS=" - The Headset is asking to send DTMF digits
"AT+CHLD=" - The Headset is asking to put the call on Hold
"AT+BVRA=" - The Headset is requesting voice recognition
"ATH" - Call hang-up

Once the parser receives one of these commands, it parses the received buffer for these character sequences and passes the parsed command back to the Handler (discussed later) as an enumeration that the Handler will be able to identify and process.

The Meat and Bones of the Interface Module
The Interface module exposes methods for signaling the Handler of network connections, listens for incoming connections and calls Handler methods of services requests.

Firstly, the Interface layer must ensure that the Bluetooth stack has been started, otherwise there's no point in processing any other commands for the network layer or the services layer. The mechanism in which the underlying layer signals that the Bluetooth stack is fully functional is via waiting on an Event Handle. Here's some code to support this:
#define BTH_NAMEDEVENT_STACK_INITED L"system/events/bluetooth/StackInitialized"
HANDLE btStack = ::OpenEvent( EVENT_ALL_ACCESS, FALSE,BTH_NAMEDEVENT_STACK_INITED );

// m_closeEvent is a previously Created Event to signal other
// waiting threads to stop waiting (created by the developer)

if( btStack && m_closeEvent )
{
HANDLE waitObjects[] = {btStack, m_closeEvent};
DWORD result = ::WaitForMultipleObjects( 2, &waitObjects[0], FALSE, INFINITE );
::CloseHandle( btStack );
if( result - WAIT_OBJECT_0 == 0 )
{
//The Bluetooth stack is up, signal core module to finish initialization
}
else if( 1 == result - WAIT_OBJECT_0 WAIT_FAILED == result )
{
// We've been signaled to close, Bluetooth stack is down!
// Or our application has signaled us to stop waiting
}
}

Here we wait on the Open Bluetooth Stack Initialized Event or our own pre-created event to indicate either the Bluetooth stack is operational or to exit, since our application is closing too.

This same scheme also works for waiting for a synchronous or asynchronous baseband connection (Which I'll discuss further in the third installment), but instead of waiting on the BTH_NAMEDEVENT_STACK_INITED wstring, we wait on the Opened Event BTH_NAMEDEVENT_CONNECTIONS_CHANGED, as defined below:
#define BTH_NAMEDEVENT_CONNECTIONS_CHANGED L"system/events/bluetooth/ConnectionsChange"

If the Interface module receives a signal of this event, it notifies the Handler module to check its baseband connections for changes.

Aside from the listening for baseband connections, or if the Bluetooth Stack is up, the Interface module also want to process service commands and network layer notifications. So, following the services interface, as mentioned in the previous article, the module needs to support:

Opening audio
Closing audio
Opening a control channel
Closing a control channel
Getting/setting the microphone volume
Getting/setting the speaker volume
Getting/setting the power mode

And these methods simply call the Handler methods for processing (Which I'll talk about more in the third installment).
For reliability, however, a developer can't create a control channel if no Bluetooth device has been paired with the WM5 device (obviously). Also, a developer can't open up a control channel without a fully initialized Interface Module (Bluetooth Stack is operational).
Secondly, you can't open an audio channel if there is no control channel open.

On the Network signaling side, the Interface Module exposes a method call to the network layer, which passes a number to identify the type of network call being signaled. The supported signaling calls are:
#define NETWORK_EVENT_CALL_IN 0x00
#define NETWORK_EVENT_CALL_OUT 0x01
#define NETWORK_EVENT_CALL_CONNECT 0x02
#define NETWORK_EVENT_CALL_DISCONNECT 0x03
#define NETWORK_EVENT_CALL_REJECT 0x04
#define NETWORK_EVENT_CALL_INFO 0x05
#define NETWORK_EVENT_CALL_BUSY 0x06
#define NETWORK_EVENT_RING 0x07

void BthAGOnNetworkEvent( DWORD dwEvent, LPSTR pszParam );

If you're designing the Interface module and the appliction accesses the network layer, you'll have to support these defines and signal your Handler class to handle these events. For more detail on these libraries, visit the MSDN website.

Important Note:
If you're developing the Interface Module alongside Microsoft's Audio Gateway, be sure that you turn off the MS AG in your Interface Module initialization code before doing anything else. If you don't, the Microsoft's AG will interfere with *your* Gateway application. The first article in this series lists code that turn offs the service. Please refer to it for the IOCTL call that corresponds to the service shutdown.

Ok, now we're getting to the really juicy part, The Handler Module. What's ticking underneath that hood, you might ask. In this article, we've explored a system level overview of the AG core and gone into details about the different responsibilities associated with the Parser Module and the Interface Module. But what ties them all together? The Handler module!

Stay tuned for a detailed description of the Handler Module...

Tuesday, April 24, 2007

 

Bluetooth Handsfree Profile Support for Windows Mobile 5 - The Series (Part 1)

Bluetooth Handsfree Profile Support for Windows Mobile 5 - Part 1

Have you ever run into the question of what mechanisms are there for supporting Bluetooth on your WM5 device? What has Microsoft provided to extend the Handsfree profile functionality? How can I use the Audio Gateway?

Very good questions. In this series of articles about Bluetooth support, I'm going to try to fill in the holes. This series is geared towards developers who have experimented with the Audio Gateway and are scratching their heads as to how to get into this "black box".

Microsoft supports Bluetooth with an architecture known as the "Audio Gateway." It consists of the core itself, the Services interface, AT Command Extension Module, Phone Extension Module, and Network Component. All of these components interact with the Core that signals the Bluetooth stack of commands and state changes. To read up on the Audio Gateway architecture, trickle into the MSDN website and search for "Bluetooth Audio Gateway."

Now, as a developer, you're wondering, "How do I get into this darn thing and make it do what I want it to do?"

There are a few ways to interact with the Audio Gateway (which I'll refer to as the "AG").

Firstly, from a services standpoint, Services.exe and the underlying layer of IOCTL calls the core support call enumerations to control the AG. I've listed the constants below. They are also in the .h file. The constants are pretty self-explanatory, so I won't go into much detail about them. Basically, there is the AG service, which we can start, stop and refresh. If the service has started and a Bluetooth device has been paired with the WM5 device, a service level connection must be established with the device as to signal different commands via AT Commands (to be discussed later), which we can start and stop as well. On top of that, the AG can route audio to the Bluetooth headset.

// You can find these within service.h
// IOCTL_SERVICE_START
// IOCTL_SERVICE_REFRESH
// IOCTL_SERVICE_STOP
// IOCTL_SERVICE_STATUS

#define IOCTL_AG_OPEN_AUDIO 0x01
#define IOCTL_AG_CLOSE_AUDIO 0x02
#define IOCTL_AG_CLOSE_CONTROL 0x03
#define IOCTL_AG_SET_SPEAKER_VOL 0x04
#define IOCTL_AG_SET_MIC_VOL 0x05
#define IOCTL_AG_GET_SPEAKER_VOL 0x06
#define IOCTL_AG_GET_MIC_VOL 0x07
#define IOCTL_AG_GET_POWER_MODE 0x08
#define IOCTL_AG_SET_POWER_MODE 0x09
#define IOCTL_AG_OPEN_CONTROL 0x0A


So, by simply calling these defines within a IOCTL call, you'll be able to achieve basic services support. Note that some defines require you to pass in values. I don't want to go into too much detail about this, since we're just scratching the surface, and I'm hoping as the reader you're asking yourself, "When does the fun really start?"

HANDLE msAGHandle = ::CreateFile( L"BAG0:", 0, 0, 0, OPEN_EXISTING, 0, 0 );
if ( INVALID_HANDLE_VALUE == msAGHandle )
{
// log something with GetLastError();
return;
}

BOOL result = ::DeviceIoControl( msAGHandle, IOCTL_SERVICE_STOP, 0, 0, 0, 0, 0, 0 );
if ( FALSE == result )
{
// log something
}

::CloseHandle( msAGHandle );


Aside from the services layer, it has been hypothesized (however not actually confirmed by me) that we can replace the AT Command Extension Module to override the AG core of AT command reception and AT command processing. What happens in the AG core, once paired and a service level connection has been established, is if an AT command is received, the core will first "ask" the AT Command Extension Module if it would like to handle this command. If the AT Command Extension Module wishes to handle the command, it returns, from the interface call, "true", otherwise "false" to signal that the core does its own processing.

So how do you replace the AT Command Extension Module?

Easy. There are two ways to replace this module. In the Windows directory of your WM5 device, a file called "btagext.dll" exposes an interface (interface description to come) which the core dynamically links to. You can replace this file with your own file to override the AT command processing. Replacing the file can get a little messy if one doesn't have the proper access rights to overwrite Windows dlls.

Another way is to edit the registry so that the AT Command Extension Module path points to your dll. First, copy your AT Command Extension DLL onto the device, edit the registry path "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Bluetooth\\AudioGateway\\BTAGExtModule" with your DLL path, restart the device or restart the AG service and... Voila!

So what does your custom AT Command Extension Module have to override?

The "btagext.dll" exposes these commands:
typedef DWORD (*PFN_SendATCommand) (LPSTR szCommand, DWORD cbCommand);
BOOL BthAGATHandler(LPSTR szCommand, DWORD cbCommand);
void BthAGATSetCallback(PFN_SendATCommand pfn);
DWORD BthAGOnVoiceTag(BOOL fOn);


I leave it up to you to explore how you can replace the AT Command Extension Module. Take a look at the MSDN Website for further details about these methods. Since we are supporting the Handsfree profile, search the Bluetooth website for the .pdf file for a list of AT commands to support... Or stay tuned for a description of these AT commands.

OK, now for the really fun stuff.

I know some of you are in the same boat as I was, saying to yourself, "I've paired and authenticated with the device, so how do I use the AG to route audio? I can route audio via the IOCTL calls but I can't do any other in-call processing. Some libraries offered in WinCE are not exposed to me, e.g. the Network component (for network signalling), so I can't signal different in-call states."

Personally, I've never gotten around to using the AG service, since specific libraries in the WM5 PPC and Smartphone SDK weren't included in my version and, simply put, I had no mechanism to control the AG service besides the service component via IOCTL calls.

What to do, what to do?! Hey lets build our own Audio Gateway! Yeah! That'll be fun!

To be continued....

Friday, April 20, 2007

 

A revival of the BIOS?

With the long load times of most major OS's, it's getting very frustrating to turn on your computer when you just need a simple piece of information. For example, if I need show the pictures I took from my weekend of antique shopping, I need to wait for Windows to boot. Even on a system in hibernation, it might take almost a minute.

What if I could write an application that didn't need Windows to run? Run it straight in the BIOS.

Extensible Firmware Interface (EFI), is a technology that Intel has co-developed to replace the venerable BIOS architecture found in x86 PCs. Like the standard BIOS, it is possible to write applications in the pre-boot environment of EFI. However, EFI offers has a much richer environment to application developers, including some really cool capabilities:
Although the EFI environment is friendlier to the application developer than standard BIOS, it does have some pretty big limitations:
The second limitation makes you realize how much work the OS does for you. This might be the single biggest hurdle to EFI application development. Maybe someone would be willing to port GTK to the EFI environment. We know it is possible to port it to an embedded environment GTK+ on DirectFB is an example of this.

Learning more

There is an open source implementation of the EFI framework that can be used as a development environment for EFI applications. You can find the information here. Although the EDK project is mostly concerned with driver development; The package contains headers and a basic build environment to construct EFI applications. It also contains a simulator to test your applications.

To write applications, you will also want to take a look at the Application Toolkit from Intel. It contains a whole bunch of utilities and libraries to assist the development of pre-boot applications.

We're not there yet

All of this EFI coolness might remain an artifact of the future for now. Most PCs don't implement an EFI BIOS yet. Some Itanium-based machines support it, and the new Intel-based Macs also have an EFI BIOS. Furthermore, Microsoft has announced that Vista will not support EFI for its first release. Actually, the word from Redmond is that it is unlikely that we will see support for EFI on 32bit machines. Ever. So, until you get your hands on a next-generation PC, you can always use a simulator to test out your ideas.

 

Welcome to The Macadamian Files

The goal of The Macadamian Files is to discuss in-depth the common issues and problems developers run into during the course of their day at Macadamian. The blog is language-agnostic, however language specific postings will heavily favour C/C++ issues.

The posters to this blog comprise the development team at Macadamian. As a product development outsourcing lab that specializes in new and early-stage products, we're fortunate to work on (what we think are) some of the most interesting products coming out of technology companies today, from startups like Third Brigade to leaders like Nortel and top PC manufacturers.

In terms of technologies, we've worked on everything from embedded environments to full-scale desktop applications, from writing our own pre-1.0 EJB container in '98, contributing to WINE and writing the PAL in Microsoft's Rotor, to writing SIP clients and developing full drop-in replacements for the Microsoft default resident dialer in Windows Mobile 5. We get to work on some pretty interesting projects. This blog will be about sharing some of those experiences and lessons, or at least the non-confidential ones.

This page is powered by Blogger. Isn't yours?