Publishing for Bluetooth Asia 2018 developer session: mesh session. This repo is for GenericOnOff server side firmware.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.c Source File

main.c

00001 /*
00002  * Copyright (c) 2018 Bluetooth SIG
00003  *
00004  * SPDX-License-Identifier: Apache-2.0
00005  */
00006 
00007 #include <misc/printk.h>
00008 
00009 #include <bluetooth/bluetooth.h>
00010 #include <bluetooth/mesh.h>
00011 #include <gpio.h>
00012 #include <board.h>
00013 #include <soc.h>
00014 #include <misc/printk.h>
00015 #include <ctype.h>
00016 #include <flash.h>
00017 #include <gpio.h>
00018 #include <pwm.h>
00019 
00020 #include <display/mb_display.h>
00021 
00022 #include <bluetooth/mesh.h>
00023 
00024 #define GROUP_ADDR 0xc000
00025 #define PUBLISHER_ADDR  0x000f
00026 #if !defined(NODE_ADDR)
00027 #define NODE_ADDR 0x0b02
00028 #endif
00029 
00030 /* Model Operation Codes */
00031 #define BT_MESH_MODEL_OP_GEN_ONOFF_GET      BT_MESH_MODEL_OP_2(0x82, 0x01)
00032 #define BT_MESH_MODEL_OP_GEN_ONOFF_SET      BT_MESH_MODEL_OP_2(0x82, 0x02)
00033 #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK    BT_MESH_MODEL_OP_2(0x82, 0x03)
00034 #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS   BT_MESH_MODEL_OP_2(0x82, 0x04)
00035 
00036 
00037 /* Button debounce timeout */
00038 #define BUTTON_DEBOUNCE_DELAY_MS 250
00039 
00040 /* LED matrix scroll speed */
00041 #define SCROLL_SPEED   K_MSEC(500)
00042 
00043 /* LED matrix scroll speed */
00044 #define BUZZER_PIN     EXT_P0_GPIO_PIN
00045 #define BEEP_DURATION  K_MSEC(60)
00046 
00047 /* NVM offset */
00048 #define SEQ_PER_BIT  976
00049 #define SEQ_PAGE     (NRF_FICR->CODEPAGESIZE * (NRF_FICR->CODESIZE - 1))
00050 #define SEQ_MAX      (NRF_FICR->CODEPAGESIZE * 8 * SEQ_PER_BIT)
00051 
00052 /* Key definition, it's pre-configured, not need to do provisioning. */
00053 static const u8_t net_key[16] = {
00054     0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
00055     0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
00056 };
00057 static const u8_t dev_key[16] = {
00058     0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
00059     0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
00060 };
00061 static const u8_t app_key[16] = {
00062     0xf1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
00063     0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
00064 };
00065 
00066 /* group address string. */
00067 const char *groupAddress2String[] = {
00068     "Bedroom",
00069     "Living",
00070     "Dining",
00071     "Garage"
00072 };
00073 
00074 static struct device *gpio;
00075 static struct device *nvm;
00076 static struct device *pwm;
00077 
00078 static struct k_work button_work;
00079 static struct k_work subscribe_work;
00080 static u32_t time, last_time;
00081 
00082 const u16_t net_idx;
00083 const u16_t app_idx;
00084 const u32_t iv_index;
00085 u8_t flags;
00086 u16_t addr;
00087 static u32_t seq;
00088 
00089 /* group address, initialized */
00090 u16_t groupAddress = GROUP_ADDR; 
00091 
00092 u16_t board_set_target(void)
00093 {
00094     switch (groupAddress) {
00095     case GROUP_ADDR:
00096         groupAddress++ ;
00097         break;
00098     case (GROUP_ADDR + 3):
00099         groupAddress = GROUP_ADDR;
00100         break;
00101     default:
00102         groupAddress++;
00103         break;
00104     }
00105 
00106     return groupAddress;
00107 }
00108 
00109 void board_seq_update(u32_t seq)
00110 {
00111     u32_t loc, seq_map;
00112     int err;
00113 
00114     if (seq % SEQ_PER_BIT) {
00115         return;
00116     }
00117 
00118     loc = (SEQ_PAGE + ((seq / SEQ_PER_BIT) / 32));
00119 
00120     err = flash_read(nvm, loc, &seq_map, sizeof(seq_map));
00121     if (err) {
00122         printk("flash_read err %d\n", err);
00123         return;
00124     }
00125 
00126     seq_map >>= 1;
00127 
00128     flash_write_protection_set(nvm, false);
00129     err = flash_write(nvm, loc, &seq_map, sizeof(seq_map));
00130     flash_write_protection_set(nvm, true);
00131     if (err) {
00132         printk("flash_write err %d\n", err);
00133     }
00134 }
00135 
00136 static u32_t get_seq(void)
00137 {
00138     u32_t seq_map, seq = 0;
00139     int err, i;
00140 
00141     for (i = 0; i < NRF_FICR->CODEPAGESIZE / sizeof(seq_map); i++) {
00142         err = flash_read(nvm, SEQ_PAGE + (i * sizeof(seq_map)),
00143                  &seq_map, sizeof(seq_map));
00144         if (err) {
00145             printk("flash_read err %d\n", err);
00146             return seq;
00147         }
00148 
00149         printk("seq_map 0x%08x\n", seq_map);
00150 
00151         if (seq_map) {
00152             seq = ((i * 32) +
00153                    (32 - popcount(seq_map))) * SEQ_PER_BIT;
00154             if (!seq) {
00155                 return 0;
00156             }
00157 
00158             break;
00159         }
00160     }
00161 
00162     seq += SEQ_PER_BIT;
00163     if (seq >= SEQ_MAX) {
00164         seq = 0;
00165     }
00166 
00167     if (seq) {
00168         seq_map >>= 1;
00169         flash_write_protection_set(nvm, false);
00170         err = flash_write(nvm, SEQ_PAGE + (i * sizeof(seq_map)),
00171                   &seq_map, sizeof(seq_map));
00172         flash_write_protection_set(nvm, true);
00173         if (err) {
00174             printk("flash_write err %d\n", err);
00175         }
00176     } else {
00177         printk("Performing flash erase of page 0x%08x\n", SEQ_PAGE);
00178         err = flash_erase(nvm, SEQ_PAGE, NRF_FICR->CODEPAGESIZE);
00179         if (err) {
00180             printk("flash_erase err %d\n", err);
00181         }
00182     }
00183 
00184     return seq;
00185 }
00186 
00187 static void buttonA_pressed(struct k_work *work)
00188 {
00189     struct mb_display *disp = mb_display_get();
00190 
00191     printk("buttonA_pressed\n");
00192     mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT, SCROLL_SPEED, "%s",
00193             groupAddress2String[groupAddress - GROUP_ADDR]);
00194 }
00195 
00196 static void buttonB_resubscribe(struct k_work *work)
00197 {
00198     struct mb_display *disp = mb_display_get();
00199 
00200     printk("change new group address to 0x%04x\n", board_set_target());
00201 
00202     mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT, SCROLL_SPEED, "%s",
00203         groupAddress2String[groupAddress - GROUP_ADDR]);
00204 
00205     // change model subscription
00206     bt_mesh_cfg_mod_sub_overwrite(net_idx, addr, addr, groupAddress,
00207                             BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
00208 
00209     {
00210         struct bt_mesh_cfg_hb_sub sub = {
00211             .src = PUBLISHER_ADDR,
00212             .dst = groupAddress,
00213             .period = 0x10,
00214         };
00215 
00216         bt_mesh_cfg_hb_sub_set(net_idx, addr, &sub, NULL /*&status*/);
00217     }
00218 
00219 }
00220 
00221 static void button_pressed(struct device *dev, struct gpio_callback *cb,
00222                uint32_t pins)
00223 {
00224 
00225     /*
00226      * One button press within a 1 second interval sends an on message
00227      * More than one button press sends an off message
00228      */
00229     time = k_uptime_get_32();
00230 
00231     /* debounce the switch */
00232     if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) {
00233         last_time = time;
00234         return;
00235     }
00236 
00237     if (pins & BIT(SW0_GPIO_PIN)) {
00238         k_work_submit(&button_work);
00239     }
00240     else {
00241             k_work_submit(&subscribe_work);
00242     }
00243 
00244     last_time = time;
00245 
00246 }
00247 
00248 static const struct {
00249     char  note;
00250     u32_t period;
00251     u32_t sharp;
00252 } period_map[] = {
00253     { 'C',  3822,  3608 },
00254     { 'D',  3405,  3214 },
00255     { 'E',  3034,  3034 },
00256     { 'F',  2863,  2703 },
00257     { 'G',  2551,  2407 },
00258     { 'A',  2273,  2145 },
00259     { 'B',  2025,  2025 },
00260 };
00261 
00262 static u32_t get_period(char note, bool sharp)
00263 {
00264     int i;
00265 
00266     if (note == ' ') {
00267         return 0;
00268     }
00269 
00270     for (i = 0; i < ARRAY_SIZE(period_map); i++) {
00271         if (period_map[i].note != note) {
00272             continue;
00273         }
00274 
00275         if (sharp) {
00276             return period_map[i].sharp;
00277         } else {
00278             return period_map[i].period;
00279         }
00280     }
00281 
00282     return 1500;
00283 }
00284 
00285 void board_heartbeat(u8_t hops, u16_t feat)
00286 {
00287     struct mb_display *disp = mb_display_get();
00288     const struct mb_image hops_img[] = {
00289         MB_IMAGE({ 1, 1, 1, 1, 1 },
00290              { 1, 1, 1, 1, 1 },
00291              { 1, 1, 1, 1, 1 },
00292              { 1, 1, 1, 1, 1 },
00293              { 1, 1, 1, 1, 1 }),
00294         MB_IMAGE({ 1, 1, 1, 1, 1 },
00295              { 1, 1, 1, 1, 1 },
00296              { 1, 1, 0, 1, 1 },
00297              { 1, 1, 1, 1, 1 },
00298              { 1, 1, 1, 1, 1 }),
00299         MB_IMAGE({ 1, 1, 1, 1, 1 },
00300              { 1, 0, 0, 0, 1 },
00301              { 1, 0, 0, 0, 1 },
00302              { 1, 0, 0, 0, 1 },
00303              { 1, 1, 1, 1, 1 }),
00304         MB_IMAGE({ 1, 1, 1, 1, 1 },
00305              { 1, 0, 0, 0, 1 },
00306              { 1, 0, 0, 0, 1 },
00307              { 1, 0, 0, 0, 1 },
00308              { 1, 1, 1, 1, 1 }),
00309         MB_IMAGE({ 1, 0, 1, 0, 1 },
00310              { 0, 0, 0, 0, 0 },
00311              { 1, 0, 0, 0, 1 },
00312              { 0, 0, 0, 0, 0 },
00313              { 1, 0, 1, 0, 1 })
00314     };
00315 
00316     printk("%u hops\n", hops);
00317 
00318     if (hops) {
00319         hops = min(hops, ARRAY_SIZE(hops_img));
00320         mb_display_image(disp, MB_DISPLAY_MODE_SINGLE, K_SECONDS(2),
00321                  &hops_img[hops - 1], 1);
00322     }
00323 }
00324 
00325 void board_other_dev_pressed(u16_t addr)
00326 {
00327     struct mb_display *disp = mb_display_get();
00328 
00329     printk("board_other_dev_pressed(0x%04x)\n", addr);
00330 
00331     mb_display_print(disp, MB_DISPLAY_MODE_SINGLE, K_SECONDS(2),
00332              "%c", groupAddress2String[groupAddress - GROUP_ADDR][0]);
00333 }
00334 
00335 void board_attention(bool attention)
00336 {
00337     struct mb_display *disp = mb_display_get();
00338     static const struct mb_image attn_img[] = {
00339         MB_IMAGE({ 0, 0, 0, 0, 0 },
00340              { 0, 0, 0, 0, 0 },
00341              { 0, 0, 1, 0, 0 },
00342              { 0, 0, 0, 0, 0 },
00343              { 0, 0, 0, 0, 0 }),
00344         MB_IMAGE({ 0, 0, 0, 0, 0 },
00345              { 0, 1, 1, 1, 0 },
00346              { 0, 1, 1, 1, 0 },
00347              { 0, 1, 1, 1, 0 },
00348              { 0, 0, 0, 0, 0 }),
00349         MB_IMAGE({ 1, 1, 1, 1, 1 },
00350              { 1, 1, 1, 1, 1 },
00351              { 1, 1, 0, 1, 1 },
00352              { 1, 1, 1, 1, 1 },
00353              { 1, 1, 1, 1, 1 }),
00354         MB_IMAGE({ 1, 1, 1, 1, 1 },
00355              { 1, 0, 0, 0, 1 },
00356              { 1, 0, 0, 0, 1 },
00357              { 1, 0, 0, 0, 1 },
00358              { 1, 1, 1, 1, 1 }),
00359     };
00360 
00361     if (attention) {
00362         mb_display_image(disp,
00363                  MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP,
00364                  K_MSEC(150), attn_img, ARRAY_SIZE(attn_img));
00365     } else {
00366         mb_display_stop(disp);
00367     }
00368 }
00369 
00370 static void configure_button(void)
00371 {
00372     static struct gpio_callback button_cb;
00373 
00374     /* Initialize the button debouncer */
00375     last_time = k_uptime_get_32();
00376 
00377     k_work_init(&button_work, buttonA_pressed);
00378     k_work_init(&subscribe_work, buttonB_resubscribe);
00379 
00380     gpio = device_get_binding(SW0_GPIO_NAME);
00381 
00382     gpio_pin_configure(gpio, SW0_GPIO_PIN,
00383                (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
00384                 GPIO_INT_ACTIVE_LOW));
00385     gpio_pin_configure(gpio, SW1_GPIO_PIN,
00386                (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
00387                 GPIO_INT_ACTIVE_LOW));
00388 
00389     gpio_init_callback(&button_cb, button_pressed,
00390                BIT(SW0_GPIO_PIN) | BIT(SW1_GPIO_PIN));
00391     gpio_add_callback(gpio, &button_cb);
00392 
00393     gpio_pin_enable_callback(gpio, SW0_GPIO_PIN);
00394     gpio_pin_enable_callback(gpio, SW1_GPIO_PIN);
00395 }
00396 
00397 void board_init(u16_t *addr, u32_t *seq)
00398 {
00399     struct mb_display *disp = mb_display_get();
00400 
00401     printk("SEQ_PAGE 0x%08x\n", SEQ_PAGE);
00402 
00403     nvm = device_get_binding(FLASH_DEV_NAME);
00404     pwm = device_get_binding(CONFIG_PWM_NRF5_SW_0_DEV_NAME);
00405 
00406     *addr = ( (u16_t)NRF_FICR->DEVICEADDR[0] ) & 0x7fff;
00407 
00408     printk("FICR 0x%02x\n", *addr);
00409 
00410     *seq = get_seq();
00411 
00412     mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT, SCROLL_SPEED,
00413              "%s %s", "Server", groupAddress2String[groupAddress - GROUP_ADDR]);
00414 
00415     configure_button();
00416 }
00417 
00418 static void heartbeat(u8_t hops, u16_t feat)
00419 {
00420     board_heartbeat(hops, feat);
00421 }
00422 
00423 static struct bt_mesh_cfg_srv cfg_srv = {
00424 //#if defined(CONFIG_BOARD_BBC_MICROBIT)
00425 //  .relay = BT_MESH_RELAY_ENABLED,
00426 //  //.relay = BT_MESH_RELAY_DISABLED,
00427 //  .beacon = BT_MESH_BEACON_DISABLED,
00428 //#else
00429     .relay = BT_MESH_RELAY_DISABLED,
00430     .beacon = BT_MESH_BEACON_DISABLED,
00431 //#endif
00432     .frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
00433     .default_ttl = 7,
00434 
00435     /* 3 transmissions with 20ms interval */
00436     .net_transmit = BT_MESH_TRANSMIT(2, 20),
00437     .relay_retransmit = BT_MESH_TRANSMIT(3, 20),
00438 
00439     .hb_sub.func = heartbeat,
00440 };
00441 
00442 static struct bt_mesh_cfg_cli cfg_cli = {
00443 };
00444 
00445 static void attention_on(struct bt_mesh_model *model)
00446 {
00447     printk("attention_on()\n");
00448     board_attention(true);
00449 }
00450 
00451 static void attention_off(struct bt_mesh_model *model)
00452 {
00453     printk("attention_off()\n");
00454     board_attention(false);
00455 }
00456 
00457 static const struct bt_mesh_health_srv_cb health_srv_cb = {
00458     .attn_on = attention_on,
00459     .attn_off = attention_off,
00460 };
00461 
00462 static struct bt_mesh_health_srv health_srv = {
00463     .cb = &health_srv_cb,
00464 };
00465 
00466 BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
00467 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_srv, NULL, 2 + 2);
00468 BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli, NULL, 2 + 2);
00469 
00470 
00471 static void gen_onoff_set(struct bt_mesh_model *model,
00472               struct bt_mesh_msg_ctx *ctx,
00473               struct net_buf_simple *buf)
00474 {
00475     struct mb_display *disp = mb_display_get();
00476     uint8_t value, trans;
00477     value = *buf->data++;
00478     trans = *buf->data++;
00479     
00480     printk("gen_onoff_set model 0x%04x, src 0x%04x, value:0x%02x, trans: 0x%02x\n",
00481             model->id, ctx->addr, value, trans);
00482     if(value){
00483         mb_display_print(disp, MB_DISPLAY_MODE_SINGLE, -1,
00484                      "%c", groupAddress2String[groupAddress - GROUP_ADDR][0]);
00485     }
00486     else{
00487         mb_display_stop(disp);
00488     }
00489 
00490 }
00491 
00492 static void gen_onoff_status(struct bt_mesh_model *model,
00493                  struct bt_mesh_msg_ctx *ctx,
00494                  struct net_buf_simple *buf)
00495 {
00496     printk("gen_onoff_status modelId 0x%04x, src 0x%04x\n", model->id, ctx->addr);
00497 }
00498 
00499 /*
00500  * OnOff Model Server Op Dispatch Table
00501  *
00502  */
00503 
00504 static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
00505     //{ BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get },
00506     { BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set },
00507     //{ BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack },
00508     BT_MESH_MODEL_OP_END,
00509 };
00510 
00511 static struct bt_mesh_model root_models[] = {
00512     BT_MESH_MODEL_CFG_SRV(&cfg_srv),
00513     BT_MESH_MODEL_CFG_CLI(&cfg_cli),
00514     BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
00515     BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
00516                   &gen_onoff_pub_srv, NULL),
00517 };
00518 
00519 static struct bt_mesh_elem elements[] = {
00520     BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
00521     //BT_MESH_ELEM(0, vnd_models, BT_MESH_MODEL_NONE),
00522 };
00523 
00524 static const struct bt_mesh_comp comp = {
00525     .cid = BT_COMP_ID_LF,
00526     .elem = elements,
00527     .elem_count = ARRAY_SIZE(elements),
00528 };
00529 
00530 
00531 static void configure(void)
00532 {
00533     printk("Configuring...\n");
00534 
00535     /* Add Application Key */
00536     bt_mesh_cfg_app_key_add(net_idx, addr, net_idx, app_idx, app_key, NULL);
00537 
00538     /* Bind to vendor model */
00539     bt_mesh_cfg_mod_app_bind(net_idx, addr, addr, app_idx,
00540                      BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
00541 
00542     /* Bind to Health model */
00543     bt_mesh_cfg_mod_app_bind(net_idx, addr, addr, app_idx,
00544                  BT_MESH_MODEL_ID_HEALTH_SRV, NULL);
00545 
00546     bt_mesh_cfg_mod_sub_add(net_idx, addr, addr, groupAddress,
00547                     BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
00548 
00549     {
00550         struct bt_mesh_cfg_hb_sub sub = {
00551             .src = PUBLISHER_ADDR,
00552             .dst = groupAddress,
00553             .period = 0x10,
00554         };
00555 
00556         bt_mesh_cfg_hb_sub_set(net_idx, addr, &sub, NULL);
00557         printk("Subscribing to heartbeat messages, group address: 0x%04x, %s\n",
00558             groupAddress, groupAddress2String[groupAddress - GROUP_ADDR]);
00559     }
00560 
00561     printk("Configuration complete\n");
00562 
00563 }
00564 
00565 static const u8_t dev_uuid[16] = { 0xdd, 0xdd };
00566 
00567 static const struct bt_mesh_prov prov = {
00568     .uuid = dev_uuid,
00569 };
00570 
00571 static void bt_ready(int err)
00572 {
00573     if (err) {
00574         printk("Bluetooth init failed (err %d)\n", err);
00575         return;
00576     }
00577 
00578     printk("Bluetooth initialized\n");
00579 
00580     err = bt_mesh_init(&prov, &comp);
00581     if (err) {
00582         printk("Initializing mesh failed (err %d)\n", err);
00583         return;
00584     }
00585 
00586     printk("Mesh initialized\n");
00587 
00588     err = bt_mesh_provision(net_key, net_idx, flags, iv_index, seq, addr,
00589                 dev_key);
00590     if (err) {
00591         printk("Provisioning failed (err %d)\n", err);
00592         return;
00593     }
00594 
00595     printk("Provisioning completed\n");
00596 
00597     configure();
00598 }
00599 
00600 void main(void)
00601 {
00602     int err;
00603 
00604     printk("Initializing...\n");
00605 
00606     board_init(&addr, &seq);
00607 
00608     printk("Unicast address: 0x%04x, seq 0x%06x\n", addr, seq);
00609 
00610     /* Initialize the Bluetooth Subsystem */
00611     err = bt_enable(bt_ready);
00612     if (err) {
00613         printk("Bluetooth init failed (err %d)\n", err);
00614     }
00615 
00616     while (1) {
00617     }
00618 
00619 }