nRF BLINKY compatible firmware using Zephyr Bluetooth APIs

Hello World !!

This is simple code which is compatible for nRF Blinky App which is based on Zephyr OS Bluetooth APIs. I've tested it on #nRF52840-PDK board. Isn't it simple ?

You have to just replace $zephyr_base/samples/bluetooth/peripheral/src/main.c with following code.

These are some useful links for reference,

( https://play.google.com/store/apps/details?id=no.nordicsemi.android.nrfblinky&hl=en )

(http://docs.zephyrproject.org/api/bluetooth.html )

(http://docs.zephyrproject.org/samples/bluetooth/bluetooth.html#bluetooth-setup)

#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <misc/printk.h>
#include <misc/byteorder.h>
#include <zephyr.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>

#define DEVICE_NAME		CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN		(sizeof(DEVICE_NAME) - 1)

#include <nrf.h>
#include <device.h>
#include <gpio.h>
#include <board.h>

#define  SETB(x,y)   (x|=(1<<y))     //for o/p
#define  CLRB(x,y)   (x&=(~(1<<y)))  //for o/p
#define  TGLB(x,y)   (x^=(1<<y))     //for o/p
#define  CHECKB(x,y) (x&(1<<y))      //for i/p

/* Custom Service Variables */
static struct bt_uuid_128 srv_uuid = BT_UUID_INIT_128(
	0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15,
	0xde, 0xef, 0x12, 0x12, 0x23, 0x15, 0x00, 0x00);

static struct bt_uuid_128 button_uuid = BT_UUID_INIT_128(
	0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15,
	0xde, 0xef, 0x12, 0x12, 0x24, 0x15, 0x00, 0x00);

static struct bt_uuid_128 led_uuid = BT_UUID_INIT_128(
	0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15,
	0xde, 0xef, 0x12, 0x12, 0x25, 0x15, 0x00, 0x00);


static u8_t led_value;
static u8_t button_value;

static struct bt_gatt_ccc_cfg vnd_ccc_cfg[BT_GATT_CCC_MAX] = {};
static u8_t simulate_vnd;

static ssize_t read_led(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset);
static ssize_t write_led(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, u16_t len, u16_t offset, u8_t flags);
static ssize_t read_button(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset);
static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, u16_t value);

/* Vendor Primary Service Declaration */
static struct bt_gatt_attr vnd_attrs[] = 
{
	/* Vendor Primary Service Declaration */
	BT_GATT_PRIMARY_SERVICE(&srv_uuid),

	BT_GATT_CHARACTERISTIC(&button_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY),
	BT_GATT_DESCRIPTOR(&button_uuid.uuid, BT_GATT_PERM_READ, read_button, NULL, &button_value),
	BT_GATT_CCC(vnd_ccc_cfg, vnd_ccc_cfg_changed),

	BT_GATT_CHARACTERISTIC(&led_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE),
	BT_GATT_DESCRIPTOR(&led_uuid.uuid, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_led, write_led, &led_value),
};

static struct bt_gatt_service vnd_svc = BT_GATT_SERVICE(vnd_attrs);

static const struct bt_data ad[] = 
{
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA_BYTES(BT_DATA_UUID128_ALL,
		          0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15,
	              0xde, 0xef, 0x12, 0x12, 0x23, 0x15, 0x00, 0x00),
};

static const struct bt_data sd[] = 
{
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};


static void bt_ready(int err)
{
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return;
	}

	printk("Bluetooth initialized\n");

	bt_gatt_service_register(&vnd_svc);

	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");
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

static void connected(struct bt_conn *conn, u8_t err)
{
	if (err) 
	{
		printk("Connection failed (err %u)\n", err);
	} 
	else 
	{
		printk("Connected\n");
	}
}

static void disconnected(struct bt_conn *conn, u8_t reason)
{
	printk("Disconnected (reason %u)\n", reason);
}

static struct bt_conn_cb conn_callbacks = {
	.connected = connected,
	.disconnected = disconnected,
};

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------


static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Passkey for %s: %06u\n", addr, passkey);
}

static void auth_cancel(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Pairing cancelled: %s\n", addr);
}

static struct bt_conn_auth_cb auth_cb_display = {
	.passkey_display = auth_passkey_display,
	.passkey_entry = NULL,
	.cancel = auth_cancel,
};

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

struct device *button_device[1];

static struct k_work button_work;

static void button_pressed(struct device *dev, struct gpio_callback *cb,
		 uint32_t pins)
{
	k_work_submit(&button_work);
}

void publish(struct k_work *work)
{

	if(CHECKB(NRF_P0->IN,11)==0)
	{
		button_value=1;
	}
	else
	{
		button_value=0;
	}

	bt_gatt_notify(NULL, &vnd_attrs[2], &button_value, sizeof(button_value));
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void main(void)
{
	int err;

	static struct gpio_callback button_cb[1];
	
	k_work_init(&button_work, publish);

	button_device[0] = device_get_binding(SW0_GPIO_NAME);
	gpio_pin_configure(button_device[0], SW0_GPIO_PIN, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_PUD_PULL_UP | GPIO_INT_DEBOUNCE | GPIO_INT_DOUBLE_EDGE));
	gpio_init_callback(&button_cb[0], button_pressed, BIT(SW0_GPIO_PIN));
	gpio_add_callback(button_device[0], &button_cb[0]);
	gpio_pin_enable_callback(button_device[0], SW0_GPIO_PIN);

	NRF_P0->DIR |= 0x0001E000;      
	NRF_P0->OUTSET |= 0x0001E000;

	err = bt_enable(bt_ready);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return;
	}

	bt_conn_cb_register(&conn_callbacks);
	bt_conn_auth_cb_register(&auth_cb_display);

}


static ssize_t read_led(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset)
{	
	char *value = attr->user_data;

	return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(led_value));
}

static ssize_t write_led(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, u16_t len, u16_t offset, u8_t flags)
{
	u8_t *value = attr->user_data;

	if (offset + len > sizeof(led_value)) {
		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
	}

	memcpy(value + offset, buf, len);

	if(value[0])
	{
		led_value=1;
		NRF_P0->OUT &= ~(1<<13);
	}
	else
	{
		led_value=0;
		NRF_P0->OUT |= (1<<13);
	}

	return len;
}

static ssize_t read_button(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset)
{	
	char *value = attr->user_data;

	if(CHECKB(NRF_P0->IN,11)==0)
	{
		button_value=1;
	}
	else
	{
		button_value=0;
	}

	return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(button_value));
}

static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, u16_t value)
{
	simulate_vnd = (value == BT_GATT_CCC_INDICATE) ? 1 : 0;
	
	bt_gatt_notify(NULL, &vnd_attrs[2], &button_value, sizeof(button_value));

}
  • Hi @vikrant8051 would like to run this demo under Zephyr on the Nitrogen board.

    I have tried compiling the app in the latest version of Zephyr (1.14.0) but the major problem is the two macros BT_GATT_CHARACTERISTIC and BT_GATT_DESCRIPTOR seem to have changed. BT_GATT_CHARACTERISTIC now wants 6 parameters, and BT_GATT_DESCRIPTOR is no longer present. I tried the simple fix of 'combining' the two since it appears that the newer BT_GATT_CHARACTERISTIC is simply the combination of the two older macros.

    Other minor changes the file ../prj.conf needs CONFIG_GPIO=y added, and the LED name is slightly different on the Nitrogen board.

    The code compiles and loads cleanly, but doesn't connect to an Android phone running the companion app. Any suggestions on how I should go about debugging this?

    Thanks.

  • Would be nice to have the main.c as an attachment so it is easy to download. It would be more complete if you also state what software and their version you started with for the nRF52840 PDK ? I also assume you are using the 0.9.2 version of the nRF52840-PDK ?