You are here: Information > Use Decoder Script to Extend Frontline Products > Case Study: ATT Fixed Configuration Service

Case Study: Extending Frontline ATT Decoder for a Fixed Configuration Service

Background

Normally, services in ATT are discovered so that the configuration of the database can be as flexible as possible. In the ATT world, there are rules but freedom generally reigns supreme. The price we pay for this flexibility is that the database must be discovered.

Consider the following database: Normally, it would take a number of transactions between devices to establish these three entities because the Characteristic doesn’t have to be at handle 11

Handle Contents
10 Service UUID
11 Characteristic UUID
12 Value UUID

The database could look like this:

Handle Contents
65 Service UUID
111 Characteristic UUID
212 Value UUID

But what if, when we designed the database, we also specify the handles? We would declare the Service UUID to be the ‘base handle’. Then all other handles would be offset from that base handle.

Handle Contents
<base> Service UUID
<base +1> Characteristic UUID
<base +2> Value UUID

Now there is no need for discovery at all, other than to determine the base handle. Once that is known the rest of the handles are also known. Even discovering the service can be avoided by using the ADV_IND PDU. The specification allows for ‘additional data’. This additional data could contain the base handle.

Problem:

This minimalist approach means that the very first ATT frame in a conversation could be the exchange of meaningful information instead of some form of discovery. It also means that the Frontline sniffer is deprived of essential information for decoding that meaningful information. The Frontline decoders must be told how to decode the characteristics or all you will get is raw hex data.

Solution:

The Frontline architecture allows for extensions by customers without actually modifying the Frontline decoders.

In this exercise, we will be doing the following:

  1. We insert code into the Frontline le_adv decoder to detect an advertisement of your service. We will extract the base handle from the ‘additional data’ field of the ADV_IND PDU.
  2. We insert code into the Frontline le_adv decoder to detect a CONN_REQ PDU that signals the beginning of a conversation. If we have the base handle, we will manually insert UUID/handling mappings for use by the ATT layer
  3. We will insert code into the Frontline ATT decoder to detect and decode your service characteristics.

Procedure

Note: This procedure is fairly involved. Feel free to consult with Frontline Tech Support for assistance.

  1. Find the ‘\Frontline Test Equipment\My Decoders’ directory and create a file called ‘Custom Attributes ATT.dh’. Copy into that file thefollowing code. Here we have added two new UUIDs to the Frontline ATT decoder. The service UUID is informational only and will never reference any data to be decoded. The Characteristic UUID contains additional fields and contains a call to a DecoderScript GROUP that will decode that characteristic.

    Custom Attributes ATT.dh

    Table tiUUIDs APPENDS_ONLY GATT_UUIDS

    { 0x7ffffe00 "My Service" "My Service" }

    { 0x7ffffe02 "My Data" "My Data" 0 gMyData }

    ENDTABLE

     

    GROUP gMyData

    {

    FIELD myDataField (toEndOfLayer) (stringofhex) “my data”

    }

  2. Create a file in ‘\Frontline Test Equipment\My Decoders’ called ‘Custom Attributes LE_ADV.dh’. Copy into that file the following code. Here we are decoding the ‘additional data’ in ADV_IND PDUs. Notice that we are also appending table GATT_UUIDS in le_ADV. We do this so that the service UUID will be properly decoded in both decoders. It just so happens that the tables in both decoders have the same name.

    Custom Attributes LE_ADV.dh

    Table tiUUIDs APPENDS_ONLY GATT_UUIDS

    { 0x7ffffe00 "My Service" "My Service" }

    ENDTABLE

     

    Table tMyServiceDataTypes APPENDS_ONLY tServiceDataTypes

    { 0xabcd "MySvc” "My Service" 0 gmyServiceADData } ENDTABLE

    GROUP gmyServiceADData

    {

    FIELD BaseHandle (fixed 1) RETRIEVE (StorePersistentField "MyServiceBaseHandle") (decimal) "Base Handle"

    // any more additional data decoding you might need.

    }

  3. Create a file in ‘\Frontline Test Equipment\My Decoders’ END MAIN PATH LE_ADV.dh’. Copy into that file the following code. Here we are checking the current frame to see if we should build our database. We can’t do it in the ADV_IND because the Access_Address might not be right. We need a CONNECT_REQ for what we want to do. So we check to see if we have had an ADV_IND with the service we want and if this frame is a CONN_REQ.

    END MAIN PATH LE_ADV.dh

    // IF WE HAVE SEEN AN ADV_IND WITH THE BASE uuid, WE ARE GOOD TO GO....MAYBE

     

    GROUP gCheckBuildDB if(persistentstaticexists " MyServiceBaseHandle ")

    {

    GROUP gDoBuildDB if(fieldis equalto 0x05 adv_type) // if this is a CONNECT_REQ

    {

    GROUP gBuildMyDataBase; // Go build our database. The code for that is in Custom Attributes LE_ADV.dh

    }

    }

  4. Back to ‘Custom Attributes LE_ADV.dh’ from step 2. Copy into the end of that file the following code. Here is where we tell the ATT decoder about the mappings between handles and UUIDs. There are some supporting values created by gSetupDBID . Then it is all just repeating the same three lines of decoderscript over and over. Notice that the handle value is relative to the base handle so handle 1 (using our example) would be stored as handle 11.

    Add to: Custom Attributes LE_ADV.dh

    GROUP gBuildMyDataBase

    {

    GROUP gSetupDBID;

    // These next three lines get repeated for every UUID/handle mapping

    // you want to make. Just change the storeinteger calls with the

    // numbers you want. For each UUID/handle pair, call gStoreUUID;

     

    FIELD SetOffset_1 (fixed 0) RETRIEVE(storeinteger 1) (hex) SUPPRESS_DETAIL Store chHandle

    FIELD SetUUID_1 (fixed 0) RETRIEVE(storeinteger 0x2803) (hex) SUPPRESS_DETAIL Store ShortUUID

    GROUP gStoreUUID;

    }

    GROUP gSetupDBID

    {

    FIELD GetSide (fixed 0) RETRIEVE(intraframefield "side") (hex) SUPPRESS_DETAIL store side

    FIELD MyBaseHandle (fixed 0) RETRIEVE(persistentfield " MyServiceBaseHandle") (hex) SUPPRESS_DETAIL

    // Create DBID which is Access Address + Role

    FIELD sideIs0 (Fixed 0) if(fieldis equalto 0 side) RETRIEVE (storeinteger 1) (decimal) SUPPRESS_DETAIL Store Role

    FIELD sideIs1 (Fixed 0) if(fieldis equalto 1 side) RETRIEVE (storeinteger 0) (decimal) SUPPRESS_DETAIL Store Role

     

    FIELD LE_RequesterID (fixed 0) Retrieve(StoreField AccessAddress) also (shiftleft 8) also (addfield role) also (shiftleft 16) (hex) DBID Store DBID

    }

     

    GROUP gStoreUUID

    {

    FIELD MyAbsoluteHandle (fixed 0) RETRIEVE(storefield chHandle) also (addfield MyBaseHandle) (hex) SUPPRESS_DETAIL

    FIELD gUniqueHandle (fixed 0) RETRIEVE(StoreField DBID) also (AddField MyAbsoluteHandle) (hex) SUPPRESS_DETAIL

    FIELD chUUIDShrtStore (fixed 0) PROCESSING(ATTSetUUIDMapping ATTMappings gUniqueHandle ShortUUID ) (Hex) SUPPRESS_DETAIL // Store mapping

    }