Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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