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

}
Anonymous
  • I used Zephyr latest kernel version 1.10.0 (Dec 2017) + Zephyr SDK Tools version 0.9.2

    After properly installing above two things,

    cd $zephyr_base/samples/bluetooth

    mkdir build

    cd build

    cmake -DBOARD=nrf52840_pca10056 ..

    cd zephyr

    make clean

    make all

    After that you will find zephyr.hex which you can flash into nrf52840-PDK board using nrfjtool utility.

  • 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 ?