GATT events for stanadard BLE services

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hi,

   

Is it possible to handle the GATT events in the app level for the BLE standard services such as device information service, battery service etc.

   

I looked at the device info example application, the db values are set during main init and the read events are handled by the stack.

   

Actually we want to handle all the events at the application level as we get all information from an external MCU.

   

Thanks & Regards,

   

Sharan

0 Likes
1 Solution
Anonymous
Not applicable

Hello Sharan,

   

You may want to check out the recently released EZ-Serial firmware platform:

   

http://www.cypress.com/documentation/software-and-drivers/ez-serial-ez-ble-module-firmware-platform

   

The User Guide available on that page contains all of the information you should need to tell whether it would be a good fit for what you're trying to do.

   

This platform or something like it will be necessary to do what you need; there is no universal protocol for exposing general host-level BLE events to an external MCU, so it has to be implemented in module application firmware by bridging the BLE Component APIs to some kind of host interface. EZ-Serial does this using a text-mode or binary-mode serial protocol over the UART interface.

   

Jeff

View solution in original post

0 Likes
13 Replies
Anonymous
Not applicable

All the standard service events are handled in the stack. Please check the BLE_eventhandler.c for the event handlers.

0 Likes
Anonymous
Not applicable

Hi,

   

That didn't answer my question.

   

I meant what do I need to do in order to receive the standard service events. As I said in my earlier post that we require these events to be handled in the application because we are interfacing with an external MCU.

   

Please let me know is there way to receive these events?

   

Thanks & Regards,

   

Sharan

0 Likes
Anonymous
Not applicable

Hello Sharan,

   

You may want to check out the recently released EZ-Serial firmware platform:

   

http://www.cypress.com/documentation/software-and-drivers/ez-serial-ez-ble-module-firmware-platform

   

The User Guide available on that page contains all of the information you should need to tell whether it would be a good fit for what you're trying to do.

   

This platform or something like it will be necessary to do what you need; there is no universal protocol for exposing general host-level BLE events to an external MCU, so it has to be implemented in module application firmware by bridging the BLE Component APIs to some kind of host interface. EZ-Serial does this using a text-mode or binary-mode serial protocol over the UART interface.

   

Jeff

0 Likes
Anonymous
Not applicable

Hi Jrow,

   

I understand what you're trying to say but we don't need serial like BLE module. We writing our complete application firmware on Cypress BLE chip. We have an external MCU for some other reasons.

   

But we want handle all the servers events(standard and custom services) at the app level(BLE event callback). For e.g Is it possible to handle the read request of the device info service characteristic at the app level and send a read response. 

   

This is quite possible in most of the BLE solutions in the market.

   

Note:

   

Currently we are evaluating the Cypress BLE 4.2 chip for our future products.

   

Thanks & Regards,

   

Sharan

0 Likes
Anonymous
Not applicable

Hi Sharan,

   

In this case, yes, it is possible to do this with your own custom application as well. There are two options; first is to enable all events being passed up to the application by setting the correct flag:

   

cyBle_eventHandlerFlag |= CYBLE_ENABLE_ALL_EVENTS;

   

This will retain the built-in functionality, but also allow the event to reach the application callback handler after the component callback handlers processes it.

   

The other option is to augment or modify the code in the Generated_Source folder that PSoC Creator builds for the application. For example, tweaking the #define macros in the BLEName_gatt.h file starting usually around line 50 or so where various profiles are enabled:

   

#define CYBLE_DIS
#define CYBLE_DIS_SERVER

   

If you comment these lines out or remove them entirely, then the component's built-in event handlers for these profiles won't be run, and only your application handler will receive them. Also, keep in mind that this approach--modifying PSoC Creator generated code--will require re-applying those modifications any time the code is regenerated. This occurs after a "clean" operation or after any change to the project schematic or design-wide resources.

   

The specific case you mention as an example (read request to allow the application to intercept the response) is handled via the CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ event, described in the source code with the following comment:

   

   /** Event parameter type is CYBLE_GATTS_CHAR_VAL_READ_REQ_T. It is triggered on server side
       when client sends read request and when characteristic has CYBLE_GATT_DB_ATTR_CHAR_VAL_RD_EVENT
       property set. This event could be ignored by application unless it need to response by error response which
       needs to be set in gattErrorCode field of event parameter. */

   

Note that the event parameter, a pointer to data of type CYBLE_GATTS_CHAR_VAL_READ_REQ_T, does not have a structure field for the actual data which is returned. In other words, the event parameter (pointer) does not provide a way to change the value data that is sent back to the client. However, the parameter does include the attribute handle, and with this you should be able to modify the contents of the attribute with the CyBle_GattsWriteAttributeValue API method.

   

I am not certain whether this occurs before or after the attribute data has been loaded into the packet buffer for transmission, but I would assume for efficiency's sake (in case an error code is set) that it happens before.

Anonymous
Not applicable

Hi Jrow,

   

Appreciate the detailed explanation. Thank you very much.

   

I hope that packet buffer is loaded after responding to the CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ. Otherwise it would be tricky for the application's logic.  If not isn't it a good idea to fix it?

   

Anyways I'll verify the behavior.

   

Thanks & Regards,

   

Sharan

0 Likes
Anonymous
Not applicable

Hi Jrow,

   

Can you please tell me how to enable all the events programmatically, is there an API available?

   

cyBle_eventHandlerFlag |= CYBLE_ENABLE_ALL_EVENTS;

   

Thanks & Regards,

   

Sharan

0 Likes
Anonymous
Not applicable

Hi Sharan,

   

The line of code directly assigning the CYBLE_ENABLE_ALL_EVENTS bitmask to the cyBle_eventHandlerFlag variable is the only way that I know of to set that flag. I don't believe there is a separate API to set it.

   

All events are generated internally regardless of this setting, but the component's auto-generated CyBle_EventHandler method may consume some events before your application handler gets them unless this flag is set.

Anonymous
Not applicable

Hi Jrow,

   

I tried it today, the application didn't receive the event CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ.

   

Enabled cyBle_eventHandlerFlag in the main entry to receive all the events.

   

Thanks & Regards,

   

Sharan

0 Likes
Anonymous
Not applicable

Hi Sharan,

   

In the /Generated_Source/PSoC4/BLE_gatt.c source file, there is a cyBle_gattDB[] array declaration which defines the complete GATT structure for your application. The 3rd field in each entry is the permissions value. Can you confirm that this value has the equivalent bitmask applied which matches the CYBLE_GATT_DB_ATTR_CHAR_VAL_RD_EVENT constant value, on each of the characteristic value attributes for which you want to receive the CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ event?

   

If you aren't totally sure how to do this, you can also simply copy and paste the cyBle_gattDB[] array definition from BLE_gatt.c into a reply here, and I can check it for you.

Anonymous
Not applicable

Hi Sharan,

   

From the content you provided:

   
const CYBLE_GATTS_DB_T cyBle_gattDB[0x1Eu] = {     { 0x0001u, 0x2800u /* Primary service                     */, 0x00000001u /*       */, 0x0007u, {{0x1800u, NULL}}                           },     { 0x0002u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0003u, {{0x2A00u, NULL}}                           },     { 0x0003u, 0x2A00u /* Device Name                         */, 0x00000201u /* rd    */, 0x0003u, {{0x0013u, (void *)&cyBle_attValuesLen[0]}} },     { 0x0004u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0005u, {{0x2A01u, NULL}}                           },     { 0x0005u, 0x2A01u /* Appearance                          */, 0x00000201u /* rd    */, 0x0005u, {{0x0002u, (void *)&cyBle_attValuesLen[1]}} },     { 0x0006u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0007u, {{0x2A04u, NULL}}                           },     { 0x0007u, 0x2A04u /* Peripheral Preferred Connection Par */, 0x00000201u /* rd    */, 0x0007u, {{0x0008u, (void *)&cyBle_attValuesLen[2]}} },     { 0x0008u, 0x2800u /* Primary service                     */, 0x00000001u /*       */, 0x000Bu, {{0x1801u, NULL}}                           },     { 0x0009u, 0x2803u /* Characteristic                      */, 0x00002001u /* ind   */, 0x000Bu, {{0x2A05u, NULL}}                           },     { 0x000Au, 0x2A05u /* Service Changed                     */, 0x00002000u /* ind   */, 0x000Bu, {{0x0004u, (void *)&cyBle_attValuesLen[3]}} },     { 0x000Bu, 0x2902u /* Client Characteristic Configuration */, 0x00000A04u /* rd,wr */, 0x000Bu, {{0x0002u, (void *)&cyBle_attValuesLen[4]}} },     { 0x000Cu, 0x2800u /* Primary service                     */, 0x00000001u /*       */, 0x001Eu, {{0x180Au, NULL}}                           },     { 0x000Du, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x000Eu, {{0x2A29u, NULL}}                           },     { 0x000Eu, 0x2A29u /* Manufacturer Name String            */, 0x00000201u /* rd    */, 0x000Eu, {{0x0015u, (void *)&cyBle_attValuesLen[5]}} },     { 0x000Fu, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0010u, {{0x2A24u, NULL}}                           },     { 0x0010u, 0x2A24u /* Model Number String                 */, 0x00000201u /* rd    */, 0x0010u, {{0x0008u, (void *)&cyBle_attValuesLen[6]}} },     { 0x0011u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0012u, {{0x2A25u, NULL}}                           },     { 0x0012u, 0x2A25u /* Serial Number String                */, 0x00000201u /* rd    */, 0x0012u, {{0x000Au, (void *)&cyBle_attValuesLen[7]}} },     { 0x0013u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0014u, {{0x2A27u, NULL}}                           },     { 0x0014u, 0x2A27u /* Hardware Revision String            */, 0x00000201u /* rd    */, 0x0014u, {{0x000Fu, (void *)&cyBle_attValuesLen[8]}} },     { 0x0015u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0016u, {{0x2A26u, NULL}}                           },     { 0x0016u, 0x2A26u /* Firmware Revision String            */, 0x00000201u /* rd    */, 0x0016u, {{0x0009u, (void *)&cyBle_attValuesLen[9]}} },     { 0x0017u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x0018u, {{0x2A28u, NULL}}                           },     { 0x0018u, 0x2A28u /* Software Revision String            */, 0x00000201u /* rd    */, 0x0018u, {{0x000Cu, (void *)&cyBle_attValuesLen[10]}} },     { 0x0019u, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x001Au, {{0x2A23u, NULL}}                           },     { 0x001Au, 0x2A23u /* System ID                           */, 0x00000201u /* rd    */, 0x001Au, {{0x0008u, (void *)&cyBle_attValuesLen[11]}} },     { 0x001Bu, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x001Cu, {{0x2A2Au, NULL}}                           },     { 0x001Cu, 0x2A2Au /* IEEE 11073-20601 Regulatory Certifi */, 0x00000201u /* rd    */, 0x001Cu, {{0x0001u, (void *)&cyBle_attValuesLen[12]}} },     { 0x001Du, 0x2803u /* Characteristic                      */, 0x00000201u /* rd    */, 0x001Eu, {{0x2A50u, NULL}}                           },     { 0x001Eu, 0x2A50u /* PnP ID                              */, 0x00000201u /* rd    */, 0x001Eu, {{0x0007u, (void *)&cyBle_attValuesLen[13]}} }, };
   

...the standard "Read" permission is enabled (both in the local permissions byte (0x00000001) and the characteristic properties byte (0x00000200), but all of these are actually missing the separate bit which enables the read access event. This bit is not set by default for most characteristics since most applications don't need this event, and enabling it slows down the event processing routine ever so slightly.

   

The BLE_StackGattDb.h auto-generated source file for the latest released version of PSoC Creator + BLE component v3.10 contains the following definition for this attribute flag:

   
#define CYBLE_GATT_DB_ATTR_CHAR_VAL_RD_EVENT        0x010000u
   

This is the bit which must be set to enable the CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ event. It would need to be applied to the value attribute for the characteristic in question. For example, to set it on the Serial Number String value attribute (handle 0x0012), modify the structure to the following:

   
    { 0x0012u, 0x2A25u /* Serial Number String                */, 0x00010201u /* rd    */, 0x0012u, {{0x000Au, (void *)&cyBle_attValuesLen[7]}} },
   

Then recompile and re-test.

   

Note that you should keep separate/backup copies of all modified auto-generated source files, since the IDE will regenerate them and overwrite your changes if you modify the schematic or the design-wide resources, or "clean" the build environment and recompile. Keeping a backup copy enables you to reapply customizations with minimal effort.

0 Likes
Anonymous
Not applicable

Hi Jrow,

   

As I understood from your earlier post that we can still enable all events using the cyBle_eventHandlerFlag |= CYBLE_ENABLE_ALL_EVENTS. Isn't that possible?

   

Thanks & Regards,

   

Sharan

0 Likes
Anonymous
Not applicable

Yes, but you're talking about two different things here.

   

The CYBLE_ENABLE_ALL_EVENTS flag controls whether built-in profile handling functions fully consume certain application-level events or not. Refer to the CyBle_EventHandler() implementation in BLE_eventHandler.c for the top-level implementation of this. This event handler is called before your application-specific event handler is called, and there are some conditions inside which can prevent your application-specific event handler from being called at all.

   

For instance, the CYBLE_EVT_GATTS_WRITE_CMD_REQ case contains a large set of #ifdef-guarded calls to profile-specific event handlers such as CyBle_IassWriteCmdEventHandler(), each of which is called only if the cyBle_eventHandlerFlag still has the CYBLE_CALLBACK bit set. Many of these routines clear this flag if the event being processed matches certain criteria, e.g a bootloader command characteristic GATT write operation processed by the internal "BTS" profile functions. At the end of the CyBle_EventHandler() function, the event finally bubbles up to your application only if another method hasn't consumed it or you have explicitly set the CYBLE_ENABLE_ALL_EVENTS flag:

   
    if(0u != (cyBle_eventHandlerFlag & (CYBLE_CALLBACK | CYBLE_ENABLE_ALL_EVENTS)))     {         cyBle_eventHandlerFlag &= (uint8)~CYBLE_CALLBACK;         CyBle_ApplCallback((uint32)eventCode, eventParam);     }
   

 

   

On the other hand, the CYBLE_GATT_DB_ATTR_CHAR_VAL_RD_EVENT flag set in the GATT database definition table has a very different function. This bit controls whether the stack generates the CYBLE_EVT_GATTS_READ_CHAR_VAL_ACCESS_REQ event at all when a read occurs. If this bit is unset on any given characteristic, then it doesn't matter whether you have the CYBLE_ENABLE_ALL_EVENTS flag set or not, because that specific event will never be triggered internally.

0 Likes