Publishing for Bluetooth Asia 2018 developer session: mesh session. This repo is for GenericOnOff server side firmware.
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 }
Generated on Sat Jul 16 2022 22:00:48 by 1.7.2