Publishing for Bluetooth Asia 2018 developer session: mesh session. This repo is for GenericOnOff client side firmware.
EULA
PLEASE READ MESH_DEMO_TUTORIAL_EULA.TXT BEFORE START DEVELOPMENT.
Overview
This sample demonstrates Bluetooth Mesh functionality on micro:bit. It doesn't need provisioning because all the credential material (DevKey, NetKey, AppKey, Key Index, IVI and Unicast address) is pre-configured. This sample work as a GenericOnOff client:
- Pressing Button A on micro:bit will send GenericOnOffSet access message with on or off state alternatively and specific group address;
- Pressing Button B on micro:bit will switch the group address from 0xC000 to 0xC003 and back to 0xC000 again like round robin;
Requirements
micro:bit board
Building and Running
0. Download source code, it's zip file, the link is on this page, Download repository
.
1. Following below link to set the development environment up on your Windows computer. http://docs.zephyrproject.org/getting_started/installation_win.html . Please make sure git checkout this commit, commit: 88dfd399f480b1593a8e13f5a68d512921a55502 , the detail is here, https://github.com/zephyrproject-rtos/zephyr/commit/88dfd399f480b1593a8e13f5a68d512921a55502
2. copy zip file into ./zephyr/sample/
in the Zephyr tree.
3. unzip the file by "Extract Here".
3. access into the extracted folder and rename prj_bbc_microbit.txt
to prj_bbc_microbit.conf
4. if adopting Windows Command Prompt, use it to access into the unzip folder and type following commands on the console:
mkdir build & cd build
cmake -GNinja -DBOARD=bbc_microbit ..
ninja
if adopting MSYS2, use it to access into the unzip folder and type following commands on the console:
mkdir build & cd build
cmake -GNinja -DBOARD=bbc_microbit ..
ninja
5. connect micro:bit with your computer by USB cable, the board will be enumerated as a massive storage device;
6. drag the hex file (which is in ./zephyr/sample/[unzip folder]/build/zephyr/zephyr.hex
) into
Microbit massive storage device to flash the firmware;
7. micro:bit is ready to work as a GenericOnOff client.
Diff: src/main.c
- Revision:
- 11:4d9f3f506c13
- Parent:
- 10:f83347affca6
- Child:
- 12:2cebd2171a01
diff -r f83347affca6 -r 4d9f3f506c13 src/main.c --- a/src/main.c Sun May 27 12:30:57 2018 +0000 +++ b/src/main.c Mon May 28 09:27:47 2018 +0000 @@ -6,570 +6,3 @@ */ #include <misc/printk.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/mesh.h> -#include <gpio.h> -#include <board.h> -#include <soc.h> -#include <misc/printk.h> -#include <settings/settings.h> -#include <ctype.h> -#include <flash.h> -#include <gpio.h> -#include <pwm.h> - -#include <display/mb_display.h> - -#include <bluetooth/mesh.h> - -#if !defined(NODE_ADDR) -#define NODE_ADDR 0x0b02 -#endif - -#define CID_INTEL 0x0002 -#define MOD_INTEL 0x0000 -#define GROUP_ADDR 0xc000 -#define PUBLISHER_ADDR 0x000f - -/* Model Operation Codes */ -#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01) -#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02) -#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) -#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) - -/* Publication Declarations */ -BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0); -BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli, NULL, 2 + 2); - -/* Button debounce timeout */ -#define BUTTON_DEBOUNCE_DELAY_MS 250 - -/* LED matrix scroll speed */ -#define SCROLL_SPEED K_MSEC(500) - -/* Buzzer definition, no used in this example. */ -#define BUZZER_PIN EXT_P0_GPIO_PIN -#define BEEP_DURATION K_MSEC(60) - -/* Key definition, it's pre-configured, not need to do provisioning. */ -static const u8_t net_key[16] = { - 0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, -}; -static const u8_t dev_key[16] = { - 0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, -}; -static const u8_t app_key[16] = { - 0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, -}; - - -/* group address string. */ -const char *groupAddress2String[] = { - "Bedroom", - "Living", - "Dining", - "Garage" -}; - -static struct device *gpio; -static struct device *nvm; -static struct device *pwm; - -static struct k_work button_work; -static u32_t time, last_time; - -const u16_t net_idx; -const u16_t app_idx; -const u32_t iv_index; -u8_t flags; -u16_t addr = NODE_ADDR; -u16_t groupAddress = GROUP_ADDR; - -/* Transaction ID for Generic OnOff Set */ -static u8_t trans_ID = 0; - -/* GenericOnOffSet state */ -u8_t OnOff_Value = 0; - -/* Model Operation decleration */ -static void gen_onoff_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf); - -static void gen_onoff_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf); - -static void gen_onoff_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf); - -static void gen_onoff_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf); -static void genericOnOffSet(void); - - -/* switch group address like round robin. */ -u16_t board_set_target(void) -{ - switch (groupAddress) { - case GROUP_ADDR: - groupAddress++; - break; - case (GROUP_ADDR + 3): - groupAddress = GROUP_ADDR; - break; - default: - groupAddress++; - break; - } - - return groupAddress; -} - -/* Callback function for button B pressed, it's scheduled by OS, out of interrupt routine - * it's safe to stay here longer. */ -static void button_send_pressed(struct k_work *work) -{ - struct mb_display *disp = mb_display_get(); - - printk("button_send_pressed()\n"); - if(OnOff_Value % 2) { - mb_display_print(disp, MB_DISPLAY_MODE_SINGLE, 100000, - "%s", groupAddress2String[groupAddress - GROUP_ADDR]); - } - else - { - mb_display_print(disp, MB_DISPLAY_MODE_SINGLE, 100000, - "%s", " "); - } - genericOnOffSet(); -} - -/* button B callback, direct invoke by interrupt routine, need to be out of this callback ASAP. */ -static void button_pressed(struct device *dev, struct gpio_callback *cb, - uint32_t pins) -{ - struct mb_display *disp = mb_display_get(); - - /* - * One button press within a 1 second interval sends an on message - * More than one button press sends an off message - */ - time = k_uptime_get_32(); - - /* debounce the switch */ - if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) { - last_time = time; - return; - } - - if (pins & BIT(SW0_GPIO_PIN)) { - k_work_submit(&button_work); - } - else { - board_set_target(); - - mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT, SCROLL_SPEED, - "%s", groupAddress2String[groupAddress - GROUP_ADDR]); - } - last_time = time; -} - -static const struct { - char note; - u32_t period; - u32_t sharp; -} period_map[] = { - { 'C', 3822, 3608 }, - { 'D', 3405, 3214 }, - { 'E', 3034, 3034 }, - { 'F', 2863, 2703 }, - { 'G', 2551, 2407 }, - { 'A', 2273, 2145 }, - { 'B', 2025, 2025 }, -}; - -static u32_t get_period(char note, bool sharp) -{ - int i; - - if (note == ' ') { - return 0; - } - - for (i = 0; i < ARRAY_SIZE(period_map); i++) { - if (period_map[i].note != note) { - continue; - } - - if (sharp) { - return period_map[i].sharp; - } else { - return period_map[i].period; - } - } - - return 1500; -} - - -void board_heartbeat(u8_t hops, u16_t feat) -{ - struct mb_display *disp = mb_display_get(); - const struct mb_image hops_img[] = { - MB_IMAGE({ 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }), - MB_IMAGE({ 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 0, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }), - MB_IMAGE({ 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 1, 1, 1, 1 }), - MB_IMAGE({ 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 1, 1, 1, 1 }), - MB_IMAGE({ 1, 0, 1, 0, 1 }, - { 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0 }, - { 1, 0, 1, 0, 1 }) - }; - - printk("%u hops\n", hops); - - if (hops) { - hops = min(hops, ARRAY_SIZE(hops_img)); - mb_display_image(disp, MB_DISPLAY_MODE_SINGLE, K_SECONDS(2), - &hops_img[hops - 1], 1); - } -} - -void board_attention(bool attention) -{ - struct mb_display *disp = mb_display_get(); - static const struct mb_image attn_img[] = { - MB_IMAGE({ 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 }), - MB_IMAGE({ 0, 0, 0, 0, 0 }, - { 0, 1, 1, 1, 0 }, - { 0, 1, 1, 1, 0 }, - { 0, 1, 1, 1, 0 }, - { 0, 0, 0, 0, 0 }), - MB_IMAGE({ 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 0, 1, 1 }, - { 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }), - MB_IMAGE({ 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 1 }, - { 1, 1, 1, 1, 1 }), - }; - - if (attention) { - mb_display_image(disp, - MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP, - K_MSEC(150), attn_img, ARRAY_SIZE(attn_img)); - } else { - mb_display_stop(disp); - } -} - -static void configure_button(void) -{ - static struct gpio_callback button_cb; - - /* Initialize the button debouncer */ - last_time = k_uptime_get_32(); - - k_work_init(&button_work, button_send_pressed); - - gpio = device_get_binding(SW0_GPIO_NAME); - - gpio_pin_configure(gpio, SW0_GPIO_PIN, - (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | - GPIO_INT_ACTIVE_LOW)); - gpio_pin_configure(gpio, SW1_GPIO_PIN, - (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | - GPIO_INT_ACTIVE_LOW)); - - gpio_init_callback(&button_cb, button_pressed, - BIT(SW0_GPIO_PIN) | BIT(SW1_GPIO_PIN)); - gpio_add_callback(gpio, &button_cb); - - gpio_pin_enable_callback(gpio, SW0_GPIO_PIN); - gpio_pin_enable_callback(gpio, SW1_GPIO_PIN); -} - -void board_init(u16_t *addr) -{ - struct mb_display *disp = mb_display_get(); - - nvm = device_get_binding(FLASH_DEV_NAME); - pwm = device_get_binding(CONFIG_PWM_NRF5_SW_0_DEV_NAME); - - *addr = ( (u16_t)NRF_FICR->DEVICEADDR[0] ) & 0x7fff; - printk("FICR 0x%02x\n", *addr); - - mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT, SCROLL_SPEED, - "%s %s", "Client", groupAddress2String[groupAddress - GROUP_ADDR]); - - configure_button(); -} - -static void heartbeat(u8_t hops, u16_t feat) -{ - board_heartbeat(hops, feat); -} - -static struct bt_mesh_cfg_srv cfg_srv = { -#if defined(CONFIG_BOARD_BBC_MICROBIT) - .relay = BT_MESH_RELAY_ENABLED, - .beacon = BT_MESH_BEACON_DISABLED, -#else - .relay = BT_MESH_RELAY_ENABLED, - .beacon = BT_MESH_BEACON_ENABLED, -#endif - .frnd = BT_MESH_FRIEND_NOT_SUPPORTED, - .default_ttl = 7, - - /* 3 transmissions with 20ms interval */ - .net_transmit = BT_MESH_TRANSMIT(2, 20), - .relay_retransmit = BT_MESH_TRANSMIT(3, 20), - - .hb_sub.func = heartbeat, -}; - -static struct bt_mesh_cfg_cli cfg_cli = { -}; - - -static void attention_on(struct bt_mesh_model *model) -{ - printk("attention_on()\n"); - board_attention(true); -} - -static void attention_off(struct bt_mesh_model *model) -{ - printk("attention_off()\n"); - board_attention(false); -} - -static const struct bt_mesh_health_srv_cb health_srv_cb = { - .attn_on = attention_on, - .attn_off = attention_off, -}; - -static struct bt_mesh_health_srv health_srv = { - .cb = &health_srv_cb, -}; - -/* - * OnOff Model Client Op Dispatch Table - */ - -static const struct bt_mesh_model_op gen_onoff_cli_op[] = { - { BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status }, - BT_MESH_MODEL_OP_END, -}; - -static struct bt_mesh_model root_models[] = { - BT_MESH_MODEL_CFG_SRV(&cfg_srv), - BT_MESH_MODEL_CFG_CLI(&cfg_cli), - BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), - BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, - &gen_onoff_pub_cli, NULL), -}; - -static struct bt_mesh_elem elements[] = { - BT_MESH_ELEM(0, root_models, /* vnd_models */ BT_MESH_MODEL_NONE), -}; - -static const struct bt_mesh_comp comp = { - .cid = BT_COMP_ID_LF, - .elem = elements, - .elem_count = ARRAY_SIZE(elements), -}; - -/* - * Generic OnOff Model Server Message Handlers - * - * Mesh Model Specification 3.1.1 - * - */ - -static void gen_onoff_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) -{ - printk("gen_onoff_get...\n"); -} - -static void gen_onoff_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) -{ - printk("gen_onoff_set_unack...\n"); -} - -static void gen_onoff_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) -{ - printk("gen_onoff_set...\n"); - -} - -static void gen_onoff_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) -{ - printk("gen_onoff_status...\n"); -} - -static void configure(void) -{ - int status; - - printk("Configuring...\n"); - - /* Add Application Key */ - status = bt_mesh_cfg_app_key_add(net_idx, addr, net_idx, app_idx, app_key, NULL); - printk("bt_mesh_cfg_app_key_add = %d \n", status); - - - /* Bind to Generic on/off client model */ - status = bt_mesh_cfg_mod_app_bind(net_idx, addr, addr, app_idx, - BT_MESH_MODEL_ID_GEN_ONOFF_CLI, NULL); - printk("bt_mesh_cfg_mod_app_bind = %d \n", status); - - status = bt_mesh_cfg_mod_sub_add(net_idx, addr, addr, - GROUP_ADDR, BT_MESH_MODEL_ID_GEN_ONOFF_CLI, NULL); - printk("bt_mesh_cfg_mod_sub_add = %d \n", status); - - - struct bt_mesh_cfg_hb_sub sub = { - .src = PUBLISHER_ADDR, - .dst = GROUP_ADDR, - .period = 0x10, - }; - - bt_mesh_cfg_hb_sub_set(net_idx, addr, &sub, NULL); - printk("Subscribing to heartbeat messages\n"); - - - printk("Configuration complete\n"); - -} - -static const u8_t dev_uuid[16] = { 0xdd, 0xdd }; - -static const struct bt_mesh_prov prov = { - .uuid = dev_uuid, -}; - -static void bt_ready(int err) -{ - if (err) { - printk("Bluetooth init failed (err %d)\n", err); - return; - } - - printk("Bluetooth initialized\n"); - - err = bt_mesh_init(&prov, &comp); - if (err) { - printk("Initializing mesh failed (err %d)\n", err); - return; - } - - printk("Mesh initialized\n"); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - printk("Loading stored settings\n"); - settings_load(); - } - - err = bt_mesh_provision(net_key, net_idx, flags, iv_index, addr, - dev_key); - - if (err == -EALREADY) { - printk("Using stored settings\n"); - } else if (err) { - printk("Provisioning failed (err %d)\n", err); - return; - } else { - printk("Provisioning completed\n"); - configure(); - } - - printk("Provisioning completed\n"); - - configure(); -} - -static void genericOnOffSet(void) -{ - NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + 4); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net_idx, - .app_idx = app_idx, - .addr = groupAddress, - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - - /* Bind to Generic OnOff Model */ - bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_SET ); - - net_buf_simple_add_u8(&msg, OnOff_Value % 2); - OnOff_Value++; - net_buf_simple_add_u8(&msg, trans_ID++); - - if (bt_mesh_model_send(&root_models[3], &ctx, &msg, NULL, NULL)) { - printk("Unable to send Vendor Button message\n"); - } - - printk("Button message sent with addr 0x%04x\n", groupAddress); -} - -void main(void) -{ - int err; - - printk("Initializing...\n"); - - board_init(&addr); - - printk("Unicast address: 0x%04x, name: %s\n", addr, groupAddress2String[groupAddress - GROUP_ADDR]); - - /* Initialize the Bluetooth Subsystem */ - err = bt_enable(bt_ready); - if (err) { - printk("Bluetooth init failed (err %d)\n", err); - } - - while (1) { - - } - -}