nRF5 SDK for Mesh v1.0.1
main.c
1 /* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form, except as embedded into a Nordic
11  * Semiconductor ASA integrated circuit in a product or a software update for
12  * such product, must reproduce the above copyright notice, this list of
13  * conditions and the following disclaimer in the documentation and/or other
14  * materials provided with the distribution.
15  *
16  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
17  * contributors may be used to endorse or promote products derived from this
18  * software without specific prior written permission.
19  *
20  * 4. This software, with or without modification, must only be used with a
21  * Nordic Semiconductor ASA integrated circuit.
22  *
23  * 5. Any software provided in binary form under this license must not be reverse
24  * engineered, decompiled, modified and/or disassembled.
25  *
26  * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
27  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
29  * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <stdint.h>
39 #include <string.h>
40 
41 /* HAL */
42 #include "nrf.h"
43 #include "nrf_sdm.h"
44 #include "boards.h"
45 #include "nrf_mesh_sdk.h"
46 #include "nrf_delay.h"
47 
48 /* Core */
49 #include "nrf_mesh.h"
50 #include "nrf_mesh_events.h"
51 #include "nrf_mesh_prov.h"
52 #include "nrf_mesh_assert.h"
53 #include "log.h"
54 
55 #include "access.h"
56 #include "access_config.h"
57 #include "device_state_manager.h"
58 
59 #include "config_client.h"
60 #include "health_client.h"
61 #include "simple_on_off_client.h"
62 
63 #include "simple_hal.h"
64 #include "provisioner.h"
65 
66 #include "light_switch_example_common.h"
67 #include "rtt_input.h"
68 
69 /*****************************************************************************
70  * Definitions
71  *****************************************************************************/
72 
73 #define CLIENT_COUNT (SERVER_COUNT + 1)
74 #define GROUP_CLIENT_INDEX (SERVER_COUNT)
75 #define BUTTON_NUMBER_GROUP (3)
76 #define RTT_INPUT_POLL_PERIOD_MS (100)
77 
78 /*****************************************************************************
79  * Static data
80  *****************************************************************************/
81 
82 static const uint8_t m_netkey[NRF_MESH_KEY_SIZE] = NETKEY;
83 static const uint8_t m_appkey[NRF_MESH_KEY_SIZE] = APPKEY;
84 
85 static dsm_handle_t m_netkey_handle;
86 static dsm_handle_t m_appkey_handle;
87 static dsm_handle_t m_devkey_handles[SERVER_COUNT];
88 static dsm_handle_t m_server_handles[SERVER_COUNT];
89 static dsm_handle_t m_group_handle;
90 
91 static simple_on_off_client_t m_clients[CLIENT_COUNT];
92 static health_client_t m_health_client;
93 
94 static uint16_t m_provisioned_devices;
95 static uint16_t m_configured_devices;
96 
97 /* Forward declarations */
98 static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src);
99 static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event);
100 
101 /*****************************************************************************
102  * Static functions
103  *****************************************************************************/
104 
112 static uint16_t provisioned_device_handles_load(void)
113 {
114  uint16_t provisioned_devices = 0;
115 
116  /* Load the key handles. */
117  uint32_t count = 1;
118  ERROR_CHECK(dsm_subnet_get_all(&m_netkey_handle, &count));
119  count = 1;
120  ERROR_CHECK(dsm_appkey_get_all(m_netkey_handle, &m_appkey_handle, &count));
121 
122  /* Load all the address handles. */
123  dsm_handle_t address_handles[DSM_ADDR_MAX];
124  count = DSM_NONVIRTUAL_ADDR_MAX;
125  ERROR_CHECK(dsm_address_get_all(&address_handles[0], &count));
126 
127  for (uint32_t i = 0; i < count; ++i)
128  {
129  nrf_mesh_address_t address;
130  ERROR_CHECK(dsm_address_get(address_handles[i], &address));
131 
132  /* If the address is a unicast address, it is one of the server's root element address and
133  * we have should have a device key stored for it. If not, it is our GROUP_ADDRESS and we
134  * load the handle for that.
135  */
136  if ((address.type == NRF_MESH_ADDRESS_TYPE_UNICAST) &&
137  (dsm_devkey_handle_get(address.value, &m_devkey_handles[provisioned_devices]) == NRF_SUCCESS)
138  && m_devkey_handles[provisioned_devices] != DSM_HANDLE_INVALID)
139  {
140  ERROR_CHECK(dsm_address_handle_get(&address, &m_server_handles[provisioned_devices]));
141  provisioned_devices++;
142  }
143  else if (address.type == NRF_MESH_ADDRESS_TYPE_GROUP)
144  {
145  ERROR_CHECK(dsm_address_handle_get(&address, &m_group_handle));
146  }
147  }
148 
149  return provisioned_devices;
150 }
151 
159 static uint16_t configured_devices_count_get(void)
160 {
161  uint16_t configured_devices = 0;
162  for (uint32_t i = 0; i < SERVER_COUNT; ++i)
163  {
164  dsm_handle_t address_handle = DSM_HANDLE_INVALID;
165  if ((access_model_publish_address_get(m_clients[i].model_handle,
166  &address_handle) == NRF_SUCCESS)
167  && (DSM_HANDLE_INVALID != address_handle))
168  {
169  configured_devices++;
170  }
171  else
172  {
173  /* Clients are configured sequentially. */
174  break;
175  }
176  }
177 
178  return configured_devices;
179 }
180 
181 static void access_setup(void)
182 {
183  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting up access layer and models\n");
184 
185  dsm_init();
186  access_init();
187 
188  m_netkey_handle = DSM_HANDLE_INVALID;
189  m_appkey_handle = DSM_HANDLE_INVALID;
190  for (uint32_t i = 0; i < SERVER_COUNT; ++i)
191  {
192  m_devkey_handles[i] = DSM_HANDLE_INVALID;
193  m_server_handles[i] = DSM_HANDLE_INVALID;
194  }
195  m_group_handle = DSM_HANDLE_INVALID;
196 
197  /* Initialize and enable all the models before calling ***_flash_config_load. */
198  ERROR_CHECK(config_client_init(config_client_event_cb));
199  ERROR_CHECK(health_client_init(&m_health_client, 0, health_event_cb));
200 
201  for (uint32_t i = 0; i < CLIENT_COUNT; ++i)
202  {
203  m_clients[i].status_cb = client_status_cb;
204  ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i));
205  }
206 
207  if (dsm_flash_config_load())
208  {
209  m_provisioned_devices = provisioned_device_handles_load();
210  }
211  else
212  {
213  /* Set and add local addresses and keys, if flash recovery fails. */
214  dsm_local_unicast_address_t local_address = {PROVISIONER_ADDRESS, ACCESS_ELEMENT_COUNT};
215  ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address));
216  ERROR_CHECK(dsm_address_publish_add(GROUP_ADDRESS, &m_group_handle));
217  ERROR_CHECK(dsm_subnet_add(0, m_netkey, &m_netkey_handle));
218  ERROR_CHECK(dsm_appkey_add(0, m_netkey_handle, m_appkey, &m_appkey_handle));
219  }
220 
222  {
223  m_configured_devices = configured_devices_count_get();
224  }
225  else
226  {
227  /* Bind the keys to the health client. */
228  ERROR_CHECK(access_model_application_bind(m_health_client.model_handle, m_appkey_handle));
229  ERROR_CHECK(access_model_publish_application_set(m_health_client.model_handle, m_appkey_handle));
230 
231  /* Bind the keys to the Simple OnOff clients. */
232  for (uint32_t i = 0; i < SERVER_COUNT; ++i)
233  {
234  ERROR_CHECK(access_model_application_bind(m_clients[i].model_handle, m_appkey_handle));
235  ERROR_CHECK(access_model_publish_application_set(m_clients[i].model_handle, m_appkey_handle));
236  }
237 
238  ERROR_CHECK(access_model_application_bind(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle));
239  ERROR_CHECK(access_model_publish_application_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle));
240  ERROR_CHECK(access_model_publish_address_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_group_handle));
242  }
243 
244  provisioner_init();
245  if (m_configured_devices < m_provisioned_devices)
246  {
247  provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
248  }
249  else if (m_provisioned_devices < SERVER_COUNT)
250  {
251  provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
252  }
253 }
254 
255 static uint32_t server_index_get(const simple_on_off_client_t * p_client)
256 {
257  uint32_t index = (((uint32_t) p_client - ((uint32_t) &m_clients[0]))) / sizeof(m_clients[0]);
258  NRF_MESH_ASSERT(index < SERVER_COUNT);
259  return index;
260 }
261 
262 static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src)
263 {
264  uint32_t server_index = server_index_get(p_self);
265  switch (status)
266  {
268  hal_led_pin_set(BSP_LED_0 + server_index, true);
269  break;
270 
272  hal_led_pin_set(BSP_LED_0 + server_index, false);
273  break;
274 
276  hal_led_blink_ms(LEDS_MASK, 100, 6);
277  break;
278 
279  default:
280  NRF_MESH_ASSERT(false);
281  break;
282  }
283 
284  /* Set 4th LED on when all servers are on. */
285  bool all_servers_on = true;
286  for (uint32_t i = BSP_LED_0; i < BSP_LED_0 + m_configured_devices; ++i)
287  {
288  if (!hal_led_pin_get(i))
289  {
290  all_servers_on = false;
291  break;
292  }
293  }
294 
295  hal_led_pin_set(BSP_LED_3, all_servers_on);
296 }
297 
298 static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event)
299 {
300  switch (p_event->type)
301  {
303  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node 0x%04x alive with %u active fault(s), RSSI: %d\n",
304  p_event->p_meta_data->src.value, p_event->data.fault_status.fault_array_length,
305  p_event->p_meta_data->rssi);
306  break;
307  default:
308  break;
309  }
310 }
311 
312 static void button_event_handler(uint32_t button_number)
313 {
314  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
315  if (m_configured_devices == 0)
316  {
317  __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "No devices provisioned\n");
318  return;
319  }
320  else if (m_configured_devices <= button_number && button_number != BUTTON_NUMBER_GROUP)
321  {
322  __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Device %u not provisioned yet.\n", button_number);
323  return;
324  }
325 
326  uint32_t status = NRF_SUCCESS;
327  switch (button_number)
328  {
329  case 0:
330  case 1:
331  case 2:
332  /* Invert LED. */
333  status = simple_on_off_client_set(&m_clients[button_number],
334  !hal_led_pin_get(BSP_LED_0 + button_number));
335  break;
336  case 3:
337  /* Group message: invert all LEDs. */
338  status = simple_on_off_client_set_unreliable(&m_clients[GROUP_CLIENT_INDEX],
339  !hal_led_pin_get(BSP_LED_0 + button_number), 3);
340  break;
341  default:
342  break;
343 
344  }
345 
346  if (status == NRF_ERROR_INVALID_STATE ||
347  status == NRF_ERROR_NO_MEM ||
348  status == NRF_ERROR_BUSY)
349  {
350  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
351  hal_led_blink_ms(LEDS_MASK, 50, 4);
352  }
353  else
354  {
355  ERROR_CHECK(status);
356  }
357 }
358 
359 /*****************************************************************************
360  * Event callbacks from the provisioner
361  *****************************************************************************/
362 
363 void provisioner_config_successful_cb(void)
364 {
365  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u successful\n", m_configured_devices);
366 
367  /* Set publish address for the client to the corresponding server. */
368  ERROR_CHECK(access_model_publish_address_set(m_clients[m_configured_devices].model_handle,
369  m_server_handles[m_configured_devices]));
371 
372  hal_led_pin_set(BSP_LED_0 + m_configured_devices, false);
373  m_configured_devices++;
374 
375  if (m_configured_devices < SERVER_COUNT)
376  {
377  provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
378  hal_led_pin_set(BSP_LED_0 + m_configured_devices, true);
379  }
380  else
381  {
382  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "All servers provisioned\n");
383  hal_led_blink_ms(LEDS_MASK, 100, 4);
384  }
385 }
386 
387 void provisioner_config_failed_cb(void)
388 {
389  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u failed\n", m_configured_devices);
390 
391  /* Delete key and address. */
392  ERROR_CHECK(dsm_address_publish_remove(m_server_handles[m_configured_devices]));
393  ERROR_CHECK(dsm_devkey_delete(m_devkey_handles[m_configured_devices]));
394  provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
395 }
396 
397 void provisioner_prov_complete_cb(const nrf_mesh_prov_evt_complete_t * p_prov_data)
398 {
399  /* We should not get here if all servers are provisioned. */
400  NRF_MESH_ASSERT(m_configured_devices < SERVER_COUNT);
401 
402  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Provisioning complete. Adding address 0x%04x.\n", p_prov_data->address);
403 
404  /* Add to local storage. */
405  ERROR_CHECK(dsm_address_publish_add(p_prov_data->address, &m_server_handles[m_provisioned_devices]));
406  ERROR_CHECK(dsm_devkey_add(p_prov_data->address, m_netkey_handle, p_prov_data->p_devkey, &m_devkey_handles[m_provisioned_devices]));
407 
408  /* Bind the device key to the configuration server and set the new node as the active server. */
409  ERROR_CHECK(config_client_server_bind(m_devkey_handles[m_provisioned_devices]));
410  ERROR_CHECK(config_client_server_set(m_devkey_handles[m_provisioned_devices],
411  m_server_handles[m_provisioned_devices]));
412 
413  m_provisioned_devices++;
414 
415  /* Move on to the configuration step. */
416  provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
417 }
418 
419 static void rtt_input_handler(int key)
420 {
421  if (key >= '0' && key <= '3')
422  {
423  uint32_t button_number = key - '0';
424  button_event_handler(button_number);
425  }
426 }
427 
428 int main(void)
429 {
430  __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
431  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n");
432 
433  hal_leds_init();
434  ERROR_CHECK(hal_buttons_init(button_event_handler));
435 
436  /* Set the first LED */
437  hal_led_pin_set(BSP_LED_0, true);
438  mesh_core_setup();
439  access_setup();
440  rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
441 
442  while (true)
443  {
444  (void)sd_app_evt_wait();
445  }
446 }
uint32_t access_model_publish_address_get(access_model_handle_t handle, dsm_handle_t *p_address_handle)
Gets the current publish address for the given model.
uint32_t access_model_publish_application_set(access_model_handle_t handle, dsm_handle_t appkey_handle)
Sets the application key to be used when publishing for the given model.
A Health Current Status message was received.
Definition: health_client.h:61
#define NRF_MESH_KEY_SIZE
Size (in octets) of an encryption key.
uint32_t dsm_devkey_handle_get(uint16_t unicast_address, dsm_handle_t *p_devkey_handle)
Obtains the handle for a device key.
uint32_t simple_on_off_client_set_unreliable(simple_on_off_client_t *p_client, bool on_off, uint8_t repeats)
Sets the state of the Simple OnOff Server unreliably (without acknowledgment).
uint16_t value
Address value.
Definition: nrf_mesh.h:375
uint32_t dsm_address_publish_add(uint16_t raw_address, dsm_handle_t *p_address_handle)
Adds an address to the DSM to be used as a publish address.
#define NRF_MESH_ASSERT(cond)
Run-time assertion.
uint32_t config_client_init(config_client_event_cb_t event_cb)
Initializes the configuration client.
Provisioning complete event.
The server did not reply to a Simple OnOff Set/Get.
uint32_t simple_on_off_client_init(simple_on_off_client_t *p_client, uint16_t element_index)
Initializes the Simple OnOff client.
uint32_t dsm_address_get(dsm_handle_t address_handle, nrf_mesh_address_t *p_address)
Retrieves the address for a given address handle and fills out the given nrf_mesh_address_t structure...
#define DSM_NONVIRTUAL_ADDR_MAX
Maximum number of non-virtual addresses.
uint32_t dsm_address_publish_remove(dsm_handle_t address_handle)
Removes an address that has been used as a publish address.
uint32_t config_client_server_set(dsm_handle_t server_devkey_handle, dsm_handle_t server_address_handle)
Sets the configuration server to configure.
void access_init(void)
Initializes the access layer.
uint8_t fault_array_length
Length of the fault array.
Definition: health_client.h:73
Structure representing the unicast addresses assigned to this device.
bool access_flash_config_load(void)
Recover access layer configuration from flash.
uint32_t dsm_address_handle_get(const nrf_mesh_address_t *p_address, dsm_handle_t *p_address_handle)
Retrieves the address handle for a given nrf_mesh_address_t structure.
#define DSM_ADDR_MAX
Maximum number of addresses in total.
uint16_t dsm_handle_t
DSM handle type, used for the handles returned for the each set of data added.
void access_flash_config_store(void)
Store the current state of access layer - information related to element and model configuration - in...
uint32_t health_client_init(health_client_t *p_client, uint16_t element_index, health_client_evt_cb_t evt_handler)
Initializes a health client instance.
uint32_t dsm_address_get_all(dsm_handle_t *p_address_handle_list, uint32_t *p_count)
Get a list of all address handles in the address pool.
uint32_t access_model_application_bind(access_model_handle_t handle, dsm_handle_t appkey_handle)
Binds an application key to a model.
uint32_t dsm_appkey_get_all(dsm_handle_t subnet_handle, mesh_key_index_t *p_key_list, uint32_t *p_count)
Retrieves all the application key indices of the stored application keys of a specific subnetwork...
health_client_evt_fault_status_t fault_status
Fault status data for the Current Status and Fault Status messages.
nrf_mesh_address_t src
Source address of the message.
Definition: access.h:192
uint16_t address
Unicast address for the device.
uint32_t access_model_publish_address_set(access_model_handle_t handle, dsm_handle_t address_handle)
Changes the publish address for the given model.
uint32_t dsm_devkey_delete(dsm_handle_t dev_handle)
Removes an existing device key from the device state storage.
uint32_t dsm_local_unicast_addresses_set(const dsm_local_unicast_address_t *p_address)
Set the unicast addresses of the device.
Received status ON from the server.
health_client_evt_type_t type
Type of the event.
Definition: health_client.h:97
nrf_mesh_address_type_t type
Address type.
Definition: nrf_mesh.h:373
#define LOG_CALLBACK_DEFAULT
The default callback function to use.
const uint8_t * p_devkey
Device key of the provisioned device.
uint32_t config_client_server_bind(dsm_handle_t server_devkey_handle)
Binds the configuration client to a server.
int8_t rssi
RSSI value for the received message.
Definition: access.h:198
const access_message_rx_meta_t * p_meta_data
Meta data for the received message.
Definition: health_client.h:98
uint32_t dsm_appkey_add(mesh_key_index_t app_key_id, dsm_handle_t subnet_handle, const uint8_t *p_key, dsm_handle_t *p_app_handle)
Adds an application key and its associated application key index to the device state storage...
#define DSM_HANDLE_INVALID
Invalid handle index.
Attention status event.
Definition: health_client.h:95
Bluetooth Mesh address.
Definition: nrf_mesh.h:370
uint32_t dsm_subnet_add(mesh_key_index_t net_key_id, const uint8_t *p_key, dsm_handle_t *p_subnet_handle)
Adds a subnetwork and its associated network key index to the device state storage.
bool dsm_flash_config_load(void)
Load DSM state from flash, to recover state.
Received status OFF from the server.
uint32_t simple_on_off_client_set(simple_on_off_client_t *p_client, bool on_off)
Sets the state of the Simple OnOff server.
uint32_t dsm_devkey_add(uint16_t raw_unicast_addr, dsm_handle_t subnet_handle, const uint8_t *p_key, dsm_handle_t *p_devkey_handle)
Adds a device key.
simple_on_off_status_t
Simple OnOff status codes.
uint32_t dsm_subnet_get_all(mesh_key_index_t *p_key_list, uint32_t *p_count)
Retrieves all the network key indices of the stored subnetworks.
#define ACCESS_ELEMENT_COUNT
The number of elements in the application.
void dsm_init(void)
Initialize the device state manager.
Unicast address.
Definition: nrf_mesh.h:358

Documentation feedback | Developer Zone | Subscribe | Updated