examples of simple peripheral/central ble transmission nrf52 series

I am very familiar with PICs and some atmega stuff, just graduated university ee and the project I am working on requires transmitting very small amounts of data continuously via ble protocol. Actually transmitting real time gyroscope data. Nrf modules seemed the easiest/cheapest for our purpose and decided we would most likely end up going with someones 52 series module. I have been playing around awhile with the nordic 52 development board however I am finding the learning curve fairly steep with zephyr. I can do basic stuff, gpio, pwm, interrupts etc but am struggling with bluetooth. Would it be possible to get an example of a central device and peripheral device with a custom service and characteristic 128, that simply sends or receives 24 or more bits of data at a time.   I'm really trying to learn this and just feel myself lost, thanks.  I have been through many of the peripheral and central zephyr examples.

Parents
  • Hi,

    Yes, you may keep this ticket open if you would like so for follow up questions which are related to the topic in this ticket. If you have new questions, I will of course try to reply and answer to them, but I would recommend to create new tickets for unique questions and cases.

    And also yes, I would say this type of ticket is something that is perfect as a public ticket as there are very likely more out there with the same questions and in the same situation, so go ahead and convert it if you're comfortable with that!

    Kind regards,
    Andreas

  • after much experimenting I seem to be getting this error from the second example. 

  • ////this is .h
    
    #include <zephyr.h>
    #include <logging/log.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    #include <bluetooth/hci.h>
    
    #define MY_SERVICE_UUID 0xd4, 0x86, 0x48, 0x24, 0x54, 0xB3, 0x43, 0xA1, \
    			            0xBC, 0x20, 0x97, 0x8F, 0xC3, 0x76, 0xC2, 0x75
    
    #define RX_CHARACTERISTIC_UUID  0xA6, 0xE8, 0xC4, 0x60, 0x7E, 0xAA, 0x41, 0x6B, \
    			                    0x95, 0xD4, 0x9D, 0xCC, 0x08, 0x4F, 0xCF, 0x6A
    
    #define TX_CHARACTERISTIC_UUID  0xED, 0xAA, 0x20, 0x11, 0x92, 0xE7, 0x43, 0x5A, \
    			                    0xAA, 0xE9, 0x94, 0x43, 0x35, 0x6A, 0xD4, 0xD3
    
    /** @brief Callback type for when new data is received. */
    typedef void (*data_rx_cb_t)(uint8_t *data, uint8_t length);
    
    /** @brief Callback struct used by the my_service Service. */
    struct my_service_cb 
    {
    	/** Data received callback. */
    	data_rx_cb_t    data_rx_cb;
    };
    
    int my_service_init(void);
    
    void my_service_send(struct bt_conn *conn, const uint8_t *data, uint16_t len);
    
    
    
    

  • ///main file
    /*
     * Copyright (c) 2012-2014 Wind River Systems, Inc.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <logging/log.h>
    #include <dk_buttons_and_leds.h>
    #include "remote.h"
    
    
    #define DEVICE_NAME             CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN         (sizeof(DEVICE_NAME) - 1)
    
    static K_SEM_DEFINE(ble_init_ok, 0, 1);
    
    static const struct bt_data ad[] = 
    {
    	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static const struct bt_data sd[] = 
    {
    	BT_DATA_BYTES(BT_DATA_UUID128_ALL, MY_SERVICE_UUID),
    };
    
    struct bt_conn *my_connection;
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	struct bt_conn_info info; 
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	my_connection = conn;
    
    	if (err) 
    	{
    		printk("Connection failed (err %u)\n", err);
    		return;
    	}
    	else if(bt_conn_get_info(conn, &info))
    	{
    		printk("Could not parse connection info\n");
    	}
    	else
    	{
    		bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    		
    		printk("Connection established!		\n\
    		Connected to: %s					\n\
    		Role: %u							\n\
    		Connection interval: %u				\n\
    		Slave latency: %u					\n\
    		Connection supervisory timeout: %u	\n"
    		, addr, info.role, info.le.interval, info.le.latency, info.le.timeout);
    	}
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	printk("Disconnected (reason %u)\n", reason);
    }
    
    static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
    {
    	//If acceptable params, return true, otherwise return false.
    	return true; 
    }
    
    static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout)
    {
    	struct bt_conn_info info; 
    	char addr[BT_ADDR_LE_STR_LEN];
    	
    	if(bt_conn_get_info(conn, &info))
    	{
    		printk("Could not parse connection info\n");
    	}
    	else
    	{
    		bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    		
    		printk("Connection parameters updated!	\n\
    		Connected to: %s						\n\
    		New Connection Interval: %u				\n\
    		New Slave Latency: %u					\n\
    		New Connection Supervisory Timeout: %u	\n"
    		, addr, info.le.interval, info.le.latency, info.le.timeout);
    	}
    }
    
    static struct bt_conn_cb conn_callbacks = 
    {
    	.connected				= connected,
    	.disconnected   		= disconnected,
    	.le_param_req			= le_param_req,
    	.le_param_updated		= le_param_updated
    };
    
    static void bt_ready(int err)
    {
    	if (err) 
    	{
    		printk("BLE init failed with error code %d\n", err);
    		return;
    	}
    
    	//Configure connection callbacks
    	bt_conn_cb_register(&conn_callbacks);
    
    	//Initalize services
    	err = my_service_init();
    
    	if (err) 
    	{
    		printk("Failed to init LBS (err:%d)\n", err);
    		return;
    	}
    
    	//Start advertising
    	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
    			      sd, ARRAY_SIZE(sd));
    	if (err) 
    	{
    		printk("Advertising failed to start (err %d)\n", err);
    		return;
    	}
    
    	printk("Advertising successfully started\n");
    
    	k_sem_give(&ble_init_ok);
    }
    
    
    static void error(void)
    {
    	while (true) {
    		printk("Error!\n");
    		/* Spin for ever */
    		k_sleep(K_MSEC(1000)); //1000ms
    	}
    }
    
    void main(void)
    {
    	
    	int err = 0;
    	uint32_t number = 0;
    
    	printk("Starting Nordic BLE peripheral tutorial\n");
    
    	
    	err = bt_enable(bt_ready);
    
    	if (err) 
    	{
    		printk("BLE initialization failed\n");
    		error(); //Catch error
    	}
    	
    	/* 	Bluetooth stack should be ready in less than 100 msec. 								\
    																							\
    		We use this semaphore to wait for bt_enable to call bt_ready before we proceed 		\
    		to the main loop. By using the semaphore to block execution we allow the RTOS to 	\
    		execute other tasks while we wait. */	
    	err = k_sem_take(&ble_init_ok, K_MSEC(500));
    
    	if (!err) 
    	{
    		printk("Bluetooth initialized\n");
    	} else 
    	{
    		printk("BLE initialization did not complete in time\n");
    		error(); //Catch error
    	}
    
    	err = my_service_init();
    
    	for (;;) 
    	{
    		// Main loop
    		my_service_send(my_connection, (uint8_t *)&number, sizeof(number));
    		number++;
    		k_sleep(K_MSEC(1000)); // 1000ms
    	}
    }

  • #include "remote.h"
    
    #define BT_UUID_MY_SERVICE      BT_UUID_DECLARE_128(MY_SERVICE_UUID)
    #define BT_UUID_MY_SERVICE_RX   BT_UUID_DECLARE_128(RX_CHARACTERISTIC_UUID)
    #define BT_UUID_MY_SERVICE_TX   BT_UUID_DECLARE_128(TX_CHARACTERISTIC_UUID)
    
    #define MAX_TRANSMIT_SIZE 240//TODO figure this out
    
    uint8_t data_rx[MAX_TRANSMIT_SIZE];
    uint8_t data_tx[MAX_TRANSMIT_SIZE];
    
    int my_service_init(void)
    {
        int err = 0;
    
        memset(&data_rx, 0, MAX_TRANSMIT_SIZE);
        memset(&data_tx, 0, MAX_TRANSMIT_SIZE);
    
        return err;
    }
    
    /* This function is called whenever the RX Characteristic has been written to by a Client */
    static ssize_t on_receive(struct bt_conn *conn,
    			  const struct bt_gatt_attr *attr,
    			  const void *buf,
    			  uint16_t len,
    			  uint16_t offset,
    			  uint8_t flags)
    {
        const uint8_t * buffer = buf;
        
    	printk("Received data, handle %d, conn %p, data: 0x", attr->handle, conn);
        for(uint8_t i = 0; i < len; i++){
            printk("%02X", buffer[i]);
        }
        printk("\n");
    
    	return len;
    }
    
    /* This function is called whenever a Notification has been sent by the TX Characteristic */
    static void on_sent(struct bt_conn *conn, void *user_data)
    {
    	ARG_UNUSED(user_data);
    
        const bt_addr_le_t * addr = bt_conn_get_dst(conn);
            
    	printk("Data sent to Address 0x %02X %02X %02X %02X %02X %02X \n", addr->a.val[0]
                                                                        , addr->a.val[1]
                                                                        , addr->a.val[2]
                                                                        , addr->a.val[3]
                                                                        , addr->a.val[4]
                                                                        , addr->a.val[5]);
    }
    
    /* This function is called whenever the CCCD register has been changed by the client*/
    void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value)
    {
        ARG_UNUSED(attr);
        switch(value)
        {
            case BT_GATT_CCC_NOTIFY: 
                // Start sending stuff!
                break;
    
            case BT_GATT_CCC_INDICATE: 
                // Start sending stuff via indications
                break;
    
            case 0: 
                // Stop sending stuff
                break;
            
            default: 
                printk("Error, CCCD has been set to an invalid value");     
        }
    }
                            
    
    /* LED Button Service Declaration and Registration */
    BT_GATT_SERVICE_DEFINE(my_service,
    BT_GATT_PRIMARY_SERVICE(BT_UUID_MY_SERVICE),
    BT_GATT_CHARACTERISTIC(BT_UUID_MY_SERVICE_RX,
    			       BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
    			       BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, 
                       NULL, on_receive, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_MY_SERVICE_TX,
    			       BT_GATT_CHRC_NOTIFY,
    			       BT_GATT_PERM_READ,
                       NULL, NULL, NULL),
    BT_GATT_CCC(on_cccd_changed,
            BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    );
    
    /* This function sends a notification to a Client with the provided data,
    given that the Client Characteristic Control Descripter has been set to Notify (0x1).
    It also calls the on_sent() callback if successful*/
    void my_service_send(struct bt_conn *conn, const uint8_t *data, uint16_t len)
    {
        /* 
        The attribute for the TX characteristic is used with bt_gatt_is_subscribed 
        to check whether notification has been enabled by the peer or not.
        Attribute table: 0 = Service, 1 = Primary service, 2 = RX, 3 = TX, 4 = CCC.
        */
        const struct bt_gatt_attr *attr = &my_service.attrs[3]; 
    
        struct bt_gatt_notify_params params = 
        {
            .uuid   = BT_UUID_MY_SERVICE_TX,
            .attr   = attr,
            .data   = data,
            .len    = len,
            .func   = on_sent
        };
    
        // Check whether notifications are enabled or not
        if(bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) 
        {
            // Send the notification
    	    if(bt_gatt_notify_cb(conn, &params))
            {
                printk("Error, unable to send notification\n");
            }
        }
        else
        {
            printk("Warning, notification not enabled on the selected attribute\n");
        }
    }

  • attached main and header below here is my prj.conf

Reply Children
Related