Simple BLE Example?

Fugazi
Posts: 42
Joined: Wed Apr 26, 2017 9:05 pm

Simple BLE Example?

Postby Fugazi » Sun Apr 30, 2017 3:30 pm

Is there any simple BLE examples for just sending characters across BLE ?

Thanks

Phil.

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Re: Simple BLE Example?

Postby jesseb » Mon May 01, 2017 7:18 pm

You may want to use gap advertisements for this. You can use the esp_ble_gap_config_adv_data_raw or simply embed your characters into one of the fields for esp_ble_adv_data_t. There's a little overhead with this but you should still be able to do it. You would then receive data on scans.

Another possibility is using a gatt connection and having a rx characters attribute and a tx characters attribute. Tx could use notifications if needed or simply be readable. Good luck!

Fugazi
Posts: 42
Joined: Wed Apr 26, 2017 9:05 pm

Re: Simple BLE Example?

Postby Fugazi » Mon May 01, 2017 8:28 pm

Thank you for the help - do you know of any example code doing this to have a look at ? :)

Regards

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Re: Simple BLE Example?

Postby jesseb » Mon May 01, 2017 10:00 pm

Here's how I do it, I took out lots of stuff from my code that you won't need so this might not run without some changes. Also keep in mind that I'm not from espressif so this might not be the best way.

Code: Select all

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"


#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))

enum
{
    service_AppId                = 0x77,
};

enum
{
    gattServerPrimaryServiceUuid               = 0x2800,
    gattServerCharDeclarationUuid              = 0x2803,
    gattServerClientCharCfgUuid                = 0x2902,

    service_shortUuid                    = 0x1234, //MAKE THIS WHAT YOU NEED
};


enum
{
    txDataAttr_maxLen    = 20,
    rxDataAttr_maxLen    = 20,

    attrIndex_gattServer_service = 0,

    attrIndex_gattServer_incomingData,
    attrIndex_incomingData,

    attrIndex_gattServer_txData,
    attrIndex_txData,
    attrIndex_gattCharConfig_txData,

    attrIndex_num
};


/////////////////////////////////////////////////////////////////////////////
// Advertising data and params

static uint8_t service_data[16] = {
    /* LSB <--------------------------------------------------> MSB */
       //16 bytes
};


esp_ble_adv_data_t gatt_adv_data = {
        .set_scan_rsp = false,
        .include_name = true,
        .include_txpower = false,
        .min_interval = 0, //
        .max_interval = 0, //
        .appearance = 0x00,
        .manufacturer_len = 0,
        .p_manufacturer_data =  0,
        .service_data_len = 0,
        .p_service_data = NULL,
        .service_uuid_len = 16,
        .p_service_uuid = service_data,
        .flag = ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT,
    };

esp_ble_adv_params_t gatt_adv_params = {
        .adv_int_min        = 0x20,
        .adv_int_max        = 0x40,
        .adv_type           = ADV_TYPE_IND,
        .own_addr_type      = BLE_ADDR_TYPE_RANDOM,
    //    .peer_addr          =
    //    .peer_addr_type     = BLE_ADDR_TYPE_PUBLIC,
        .channel_map        = ADV_CHNL_ALL,
        .adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
    };



/////////////////////////////////////////////////////////////////////////////
// Service and characteristic table
static const uint16_t service_uuid = service_shortUuid;

static const uint16_t primary_service_uuid          = gattServerPrimaryServiceUuid;
static const uint16_t character_declaration_uuid    = gattServerCharDeclarationUuid;
static const uint16_t character_client_config_uuid  = gattServerClientCharCfgUuid;

static const uint8_t char_prop_notify       = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read_notify  = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read         = ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_write        = ESP_GATT_CHAR_PROP_BIT_WRITE;
static const uint8_t char_prop_read_write   = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE;

static uint8_t gattcharConfig_outgoingData[2] = {0x00, 0x00};
static uint8_t attrValue_rxData[rxDataAttr_maxLen];
static uint8_t attrValue_txData[txDataAttr_maxLen];


static uint8_t incomingData_uuid[ESP_UUID_LEN_128] = {
        //16 bytes of what you want your UUID to be
};

static uint8_t outgoingData_uuid[ESP_UUID_LEN_128] = {
        //16 bytes of what you want your UUID to be
};

/// Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t gatt_db[attrIndex_num] = {

    // Service (primary service)
    [attrIndex_gattServer_service] = {  {ESP_GATT_AUTO_RSP}
                                                     , {  ESP_UUID_LEN_16
                                                        , (uint8_t*)&primary_service_uuid
                                                        , ESP_GATT_PERM_READ
                                                        , sizeof(uint16_t)
                                                        , sizeof(service_uuid)
                                                        , (uint8_t*)&service_uuid
                                                       }
                                                    },
    // Incoming Data characteristic declaration
    [attrIndex_gattServer_rxData]        = {  {ESP_GATT_AUTO_RSP}
                                                     , {  ESP_UUID_LEN_16
                                                        , (uint8_t*)&character_declaration_uuid
                                                        , ESP_GATT_PERM_READ
                                                        , CHAR_DECLARATION_SIZE
                                                        , CHAR_DECLARATION_SIZE
                                                        , (uint8_t*)&char_prop_write
                                                       }
                                                    },
    // Incoming Data Characteristic Value
    [attrIndex_rxData]                   = {  {ESP_GATT_RSP_BY_APP}
                                                     , {  ESP_UUID_LEN_128
                                                        , (uint8_t*)incomingData_uuid
                                                        , ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE
                                                        , incomingDataAttr_maxLen
                                                        , 0
                                                        , NULL
                                                       }
                                                   },
    // Outgoing Data Characteristic Declaration
    [attrIndex_gattServer_txData]        = {  {ESP_GATT_AUTO_RSP}
                                                     , {  ESP_UUID_LEN_16
                                                        , (uint8_t*)&character_declaration_uuid
                                                        , ESP_GATT_PERM_READ
                                                        , CHAR_DECLARATION_SIZE
                                                        , CHAR_DECLARATION_SIZE
                                                        , (uint8_t*)&char_prop_read_notify
                                                       }
                                                    },
    // Outgoing Data Characteristic Value
    [attrIndex_txData]                   = {  {ESP_GATT_RSP_BY_APP}
                                                     , {  ESP_UUID_LEN_128
                                                        , (uint8_t*)outgoingData_uuid
                                                        , ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE
                                                        , outgoingDataAttr_maxLen
                                                        , 0
                                                        , NULL
                                                       }
                                                    },
    // Outgoing Data Characteristic Value - Client Characteristic Configuration Descriptor
    [attrIndex_gattCharConfig_txData]    = {  {ESP_GATT_AUTO_RSP}
                                                     , {  ESP_UUID_LEN_16
                                                        , (uint8_t*)&character_client_config_uuid
                                                        , ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE
                                                        , sizeof(uint16_t)
                                                        , sizeof(gattcharConfig_outgoingData)
                                                        , (uint8_t *)&gattcharConfig_outgoingData
                                                       }
                                                    },
};

uint16_t handle_table[attrIndex_num];

/////////////////////////////////////////////////////////////////////////////
// Other variables

static uint16_t getAttributeIndexByHandle(uint16_t attributeHandle)
{
    uint16_t attrIndex = 0;
    uint16_t index;

    for(index = 0; index < attrIndex_num; ++index)
    {
        if( handle_table[index] == attributeHandle )
        {
            attrIndex = index;
            break;
        }
    }

    return attrIndex;
}



/////////////////////////////////////////////////////////////////////
// Functions to handle gatt events

static void handleDisconnectEvent(void* p)
{
    REQUIRE(param);

    TRACE(("BLE GATT DISCONNECT_EVT , conn_id %x, is_conn %d\n", p->disconnect.conn_id, p->disconnect.is_connected ));
}



static void handleConnectEvent(void* p)
{
    REQUIRE(param);

    TRACE(("BLE GATT CONNECT_EVT, conn_id %x, is_conn %d\n", p->connect.conn_id, p->connect.is_connected));
}



static void handleGattReadEvent(esp_gatt_if_t gatts_if, void *param)
{
    REQUIRE(param);

    esp_gatt_rsp_t rsp;
    memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
    rsp.attr_value.handle = param->read.handle;

    int attrIndex = getAttributeIndexByHandle(param->read.handle);

    switch( attrIndex )
    {       
    case addAttrIndex_txData:
        TRACE(("Read outgoingData\n"));
        memcpy(rsp.attr_value.value, txData, txDataAttr_maxLen);
        rsp.attr_value.len = txDataAttr_maxLen;
        esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
        break;

    default:
        TRACE(("Error - attribute read has invalid handle: 0x%X\n", p->read.handle));
        esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_READ_NOT_PERMIT, NULL);
        break;
    }
}



static void handleGattWriteEvent(esp_gatt_if_t gatts_if, void *param)
{
    REQUIRE(param);

    esp_ble_gatts_cb_param_t *callbackParam = (esp_ble_gatts_cb_param_t *)param;
    esp_gatt_status_t status = ESP_GATT_OK;
    
    int attrIndex = getAttributeIndexByHandle(param->write.handle)
    
    switch( attrIndex )
    {
    case attrIndex_rxData:
        xTRACE(("Rx BLE Data\n"));
        handleBleRxData(...); //However you decide to implement
        break;

    default:
        TRACE(("Error: Attribute not writeable\n"));
        break;
    }

 
}



static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    esp_ble_gatts_cb_param_t *p = (esp_ble_gatts_cb_param_t *)param;

    switch (event) {
    case ESP_GATTS_REG_EVT:
        connectionInfo.gatt_if = gatts_if;
        esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, attrIndex_num, 0);
        main_postEvent( state_event_bleInterface_ready );
        break;
    case ESP_GATTS_READ_EVT:
        handleGattReadEvent(gatts_if, param);
        break;
    case ESP_GATTS_WRITE_EVT:
        handleGattWriteEvent(gatts_if, param);
        break;
    case ESP_GATTS_EXEC_WRITE_EVT:
        break;
    case ESP_GATTS_MTU_EVT:
    	TRACE(("MTU Size: %d, Connection ID: 0x%X\n", p->mtu.mtu, p->mtu.conn_id));
        break;
    case ESP_GATTS_CONF_EVT:    //When receive confirm, the event comes
        xTRACE(("CONFIRM EVENT\n"));
        break;
    case ESP_GATTS_UNREG_EVT:
        TRACE(("UNREG EVENT\n"));
        break;
    case ESP_GATTS_DELETE_EVT:
        break;
    case ESP_GATTS_START_EVT:
        TRACE(("SERVICE_START_EVT, status %d, service_handle %d\n", p->start.status, p->start.service_handle));
        break;
    case ESP_GATTS_STOP_EVT:
        break;
    case ESP_GATTS_CONNECT_EVT:
        handleConnectEvent(param);
        break;
    case ESP_GATTS_DISCONNECT_EVT:
        handleDisconnectEvent(param);
        break;
    case ESP_GATTS_OPEN_EVT:
    case ESP_GATTS_CANCEL_OPEN_EVT:
    case ESP_GATTS_CLOSE_EVT:
    case ESP_GATTS_LISTEN_EVT:
    case ESP_GATTS_CONGEST_EVT:
        break;
    case ESP_GATTS_CREAT_ATTR_TAB_EVT:
        if(param->add_attr_tab.num_handle == attrIndex_num)
        {
            #ifdef BLEINTERFACE_GATT_TRACE_VERBOSE
                print("HANDLES:\n");
                for(int i = 0; i < attrIndex_num; ++i)
                {
                    print("  0x%04X\n", param->add_attr_tab.handles[i]);
                }
            #endif

            memcpy(handle_table, param->add_attr_tab.handles, attrIndex_num*2);
            esp_ble_gatts_start_service(handle_table[attrIndex_gattServer_server]);
        }
        break;
    default:
        break;
    }
}



esp_err_t bleInterface_gatt_sendNotification(size_t len, uin8_t *data, uint16_t attributeHandle)
{

    while( len > 0 )
    {
        uint16_t sendSize = len > maxNotificationSize ? maxNotificationSize : len;
        
        esp_err_t error = esp_ble_gatts_send_indicate(  gatts_if
                                                      , conn_id
                                                      , attributeHandle
                                                      , sendSize
                                                      , data
                                                      , false
                                                     );
        if( error != ESP_OK )
        {
            printf("Send notification failed!\n");
            return error;
        }
        
        len -= sendSize;
    }

    return ESP_OK;
}



void bleInterface_gatt_start(void)
{
    const char* localName = "gattservername";

    esp_ble_gap_set_device_name((const char*)localName);
    esp_ble_gap_config_adv_data(&gatt_adv_data);
}



void bleInterface_gatt_init(void)
{
	//Need to make some other calls here as well. Look at esp-idf gatt_server_service_table example for that


    esp_ble_gatts_register_callback(gatts_event_handler);
    esp_ble_gatts_app_register(service_AppId);
}

Fugazi
Posts: 42
Joined: Wed Apr 26, 2017 9:05 pm

Re: Simple BLE Example?

Postby Fugazi » Mon May 01, 2017 10:06 pm

Thanks so much !! :)

User avatar
666hjk
Posts: 47
Joined: Wed Jan 12, 2022 3:09 am
Location: 小红点

Re: Simple BLE Example?

Postby 666hjk » Sun Sep 18, 2022 9:45 am

Thanks Fugazi & jesseb for these post. learning something from your contribution.
学习中找战友。

Who is online

Users browsing this forum: Bing [Bot], ESP_Sprite, Google [Bot] and 96 guests