Hi,
I am currently using SEGGER Embedded Studio version 4.12, nRF5 SDK version15.2.0, nRF5 SDK for Mesh version 3.1.0, Hardware BMD-300 Evaluation Board.
i using the uart to send data over the ble mesh and all work fine. now i want to write/read user data to/from the flash from specific address that i picked.
i found that code for write and read to/from the flash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdint.h> #include <string.h> /* HAL */ #include "nrf.h" #include "nrf_sdm.h" #include "boards.h" #include "nrf_mesh_sdk.h" #include "nrf_delay.h" /* Core */ #include "nrf_mesh.h" #include "nrf_mesh_events.h" #include "nrf_mesh_prov.h" #include "nrf_mesh_assert.h" #include "log.h" #include "access.h" #include "access_config.h" #include "device_state_manager.h" #include "config_client.h" #include "health_client.h" #include "simple_on_off_client.h" #include "simple_hal.h" #include "provisioner.h" #include "light_switch_example_common.h" #include "rtt_input.h" #include "flash_manager.h" // For storing custom data in flash. /***************************************************************************** * Custom data in flash *****************************************************************************/ #define FLASH_CUSTOM_DATA_GROUP_ELEMENT 0x1ABC // A number in the range 0x0000 - 0x7EFF (flash_manager.h) #define CUSTOM_DATA_FLASH_PAGE_COUNT 1 typedef struct { uint32_t data[2]; } custom_data_format_t; // Format for the custom data static flash_manager_t m_custom_data_flash_manager; // flash manager instance /***************************************************************************** * Definitions *****************************************************************************/ #define CLIENT_COUNT (SERVER_COUNT + 1) #define GROUP_CLIENT_INDEX (SERVER_COUNT) #define BUTTON_NUMBER_GROUP (3) #define RTT_INPUT_POLL_PERIOD_MS (100) /***************************************************************************** * Static data *****************************************************************************/ static const uint8_t m_netkey[NRF_MESH_KEY_SIZE] = NETKEY; static const uint8_t m_appkey[NRF_MESH_KEY_SIZE] = APPKEY; static dsm_handle_t m_netkey_handle; static dsm_handle_t m_appkey_handle; static dsm_handle_t m_devkey_handles[SERVER_COUNT]; static dsm_handle_t m_server_handles[SERVER_COUNT]; static dsm_handle_t m_group_handle; static simple_on_off_client_t m_clients[CLIENT_COUNT]; static health_client_t m_health_client; static uint16_t m_provisioned_devices; static uint16_t m_configured_devices; /* Forward declarations */ static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src); static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event); /***************************************************************************** * Static functions *****************************************************************************/ /** * Retrieves stored device state manager configuration. * The number of provisioned devices is calculated from the number of device keys stored. The device * key for each server is stored on provisioning complete in the `provisioner_prov_complete_cb()`. * * @returns Number of provisioned devices. */ static uint16_t provisioned_device_handles_load(void) { uint16_t provisioned_devices = 0; /* Load the key handles. */ uint32_t count = 1; ERROR_CHECK(dsm_subnet_get_all(&m_netkey_handle, &count)); count = 1; ERROR_CHECK(dsm_appkey_get_all(m_netkey_handle, &m_appkey_handle, &count)); /* Load all the address handles. */ dsm_handle_t address_handles[DSM_ADDR_MAX]; count = DSM_NONVIRTUAL_ADDR_MAX; ERROR_CHECK(dsm_address_get_all(&address_handles[0], &count)); for (uint32_t i = 0; i < count; ++i) { nrf_mesh_address_t address; ERROR_CHECK(dsm_address_get(address_handles[i], &address)); /* If the address is a unicast address, it is one of the server's root element address and * we have should have a device key stored for it. If not, it is our GROUP_ADDRESS and we * load the handle for that. */ if ((address.type == NRF_MESH_ADDRESS_TYPE_UNICAST) && (dsm_devkey_handle_get(address.value, &m_devkey_handles[provisioned_devices]) == NRF_SUCCESS) && m_devkey_handles[provisioned_devices] != DSM_HANDLE_INVALID) { ERROR_CHECK(dsm_address_handle_get(&address, &m_server_handles[provisioned_devices])); provisioned_devices++; } else if (address.type == NRF_MESH_ADDRESS_TYPE_GROUP) { ERROR_CHECK(dsm_address_handle_get(&address, &m_group_handle)); } } return provisioned_devices; } /** * Gets the number of configured devices. * * We exploit the fact that the publish address of the Simple OnOff clients is set at configuration * complete, i.e., in the `provisioner_config_successful_cb()`, and simply count the number of * clients with their publish address' set. */ static uint16_t configured_devices_count_get(void) { uint16_t configured_devices = 0; for (uint32_t i = 0; i < SERVER_COUNT; ++i) { dsm_handle_t address_handle = DSM_HANDLE_INVALID; if ((access_model_publish_address_get(m_clients[i].model_handle, &address_handle) == NRF_SUCCESS) && (DSM_HANDLE_INVALID != address_handle)) { configured_devices++; } else { /* Clients are configured sequentially. */ break; } } return configured_devices; } static void access_setup(void) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting up access layer and models\n"); dsm_init(); access_init(); m_netkey_handle = DSM_HANDLE_INVALID; m_appkey_handle = DSM_HANDLE_INVALID; for (uint32_t i = 0; i < SERVER_COUNT; ++i) { m_devkey_handles[i] = DSM_HANDLE_INVALID; m_server_handles[i] = DSM_HANDLE_INVALID; } m_group_handle = DSM_HANDLE_INVALID; /* Initialize and enable all the models before calling ***_flash_config_load. */ ERROR_CHECK(config_client_init(config_client_event_cb)); ERROR_CHECK(health_client_init(&m_health_client, 0, health_event_cb)); for (uint32_t i = 0; i < CLIENT_COUNT; ++i) { m_clients[i].status_cb = client_status_cb; ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i)); } if (dsm_flash_config_load()) { m_provisioned_devices = provisioned_device_handles_load(); } else { /* Set and add local addresses and keys, if flash recovery fails. */ dsm_local_unicast_address_t local_address = {PROVISIONER_ADDRESS, ACCESS_ELEMENT_COUNT}; ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address)); ERROR_CHECK(dsm_address_publish_add(GROUP_ADDRESS, &m_group_handle)); ERROR_CHECK(dsm_subnet_add(0, m_netkey, &m_netkey_handle)); ERROR_CHECK(dsm_appkey_add(0, m_netkey_handle, m_appkey, &m_appkey_handle)); } if (access_flash_config_load()) { m_configured_devices = configured_devices_count_get(); } else { /* Bind the keys to the health client. */ ERROR_CHECK(access_model_application_bind(m_health_client.model_handle, m_appkey_handle)); ERROR_CHECK(access_model_publish_application_set(m_health_client.model_handle, m_appkey_handle)); /* Bind the keys to the Simple OnOff clients. */ for (uint32_t i = 0; i < SERVER_COUNT; ++i) { ERROR_CHECK(access_model_application_bind(m_clients[i].model_handle, m_appkey_handle)); ERROR_CHECK(access_model_publish_application_set(m_clients[i].model_handle, m_appkey_handle)); } ERROR_CHECK(access_model_application_bind(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle)); ERROR_CHECK(access_model_publish_application_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle)); ERROR_CHECK(access_model_publish_address_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_group_handle)); access_flash_config_store(); } provisioner_init(); if (m_configured_devices < m_provisioned_devices) { provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices); } else if (m_provisioned_devices < SERVER_COUNT) { provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices); } } static uint32_t server_index_get(const simple_on_off_client_t * p_client) { uint32_t index = (((uint32_t) p_client - ((uint32_t) &m_clients[0]))) / sizeof(m_clients[0]); NRF_MESH_ASSERT(index < SERVER_COUNT); return index; } static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src) { uint32_t server_index = server_index_get(p_self); switch (status) { case SIMPLE_ON_OFF_STATUS_ON: hal_led_pin_set(BSP_LED_0 + server_index, true); break; case SIMPLE_ON_OFF_STATUS_OFF: hal_led_pin_set(BSP_LED_0 + server_index, false); break; case SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY: hal_led_blink_ms(LEDS_MASK, 100, 6); break; default: NRF_MESH_ASSERT(false); break; } /* Set 4th LED on when all servers are on. */ bool all_servers_on = true; for (uint32_t i = BSP_LED_0; i < BSP_LED_0 + m_configured_devices; ++i) { if (!hal_led_pin_get(i)) { all_servers_on = false; break; } } hal_led_pin_set(BSP_LED_3, all_servers_on); } static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event) { switch (p_event->type) { case HEALTH_CLIENT_EVT_TYPE_CURRENT_STATUS_RECEIVED: __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node 0x%04x alive with %u active fault(s), RSSI: %d\n", p_event->p_meta_data->src.value, p_event->data.fault_status.fault_array_length, p_event->p_meta_data->rssi); break; default: break; } } static void button_event_handler(uint32_t button_number) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number); if (m_configured_devices == 0) { __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "No devices provisioned\n"); return; } else if (m_configured_devices <= button_number && button_number != BUTTON_NUMBER_GROUP) { __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Device %u not provisioned yet.\n", button_number); return; } uint32_t status = NRF_SUCCESS; switch (button_number) { case 0: case 1: case 2: /* Invert LED. */ status = simple_on_off_client_set(&m_clients[button_number], !hal_led_pin_get(BSP_LED_0 + button_number)); break; case 3: /* Group message: invert all LEDs. */ status = simple_on_off_client_set_unreliable(&m_clients[GROUP_CLIENT_INDEX], !hal_led_pin_get(BSP_LED_0 + button_number), 3); break; default: break; } if (status == NRF_ERROR_INVALID_STATE || status == NRF_ERROR_NO_MEM || status == NRF_ERROR_BUSY) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n"); hal_led_blink_ms(LEDS_MASK, 50, 4); } else { ERROR_CHECK(status); } } /***************************************************************************** * Event callbacks from the provisioner *****************************************************************************/ void provisioner_config_successful_cb(void) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u successful\n", m_configured_devices); /* Set publish address for the client to the corresponding server. */ ERROR_CHECK(access_model_publish_address_set(m_clients[m_configured_devices].model_handle, m_server_handles[m_configured_devices])); access_flash_config_store(); hal_led_pin_set(BSP_LED_0 + m_configured_devices, false); m_configured_devices++; if (m_configured_devices < SERVER_COUNT) { provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices); hal_led_pin_set(BSP_LED_0 + m_configured_devices, true); } else { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "All servers provisioned\n"); hal_led_blink_ms(LEDS_MASK, 100, 4); } } void provisioner_config_failed_cb(void) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u failed\n", m_configured_devices); /* Delete key and address. */ ERROR_CHECK(dsm_address_publish_remove(m_server_handles[m_configured_devices])); ERROR_CHECK(dsm_devkey_delete(m_devkey_handles[m_configured_devices])); provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices); } void provisioner_prov_complete_cb(const nrf_mesh_prov_evt_complete_t * p_prov_data) { /* We should not get here if all servers are provisioned. */ NRF_MESH_ASSERT(m_configured_devices < SERVER_COUNT); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Provisioning complete. Adding address 0x%04x.\n", p_prov_data->address); /* Add to local storage. */ ERROR_CHECK(dsm_address_publish_add(p_prov_data->address, &m_server_handles[m_provisioned_devices])); ERROR_CHECK(dsm_devkey_add(p_prov_data->address, m_netkey_handle, p_prov_data->p_devkey, &m_devkey_handles[m_provisioned_devices])); /* Bind the device key to the configuration server and set the new node as the active server. */ ERROR_CHECK(config_client_server_bind(m_devkey_handles[m_provisioned_devices])); ERROR_CHECK(config_client_server_set(m_devkey_handles[m_provisioned_devices], m_server_handles[m_provisioned_devices])); m_provisioned_devices++; /* Move on to the configuration step. */ provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices); } static void rtt_input_handler(int key) { if (key >= '0' && key <= '3') { uint32_t button_number = key - '0'; button_event_handler(button_number); } } int main(void) { uint32_t ret_code; __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n"); hal_leds_init(); ERROR_CHECK(hal_buttons_init(button_event_handler)); /* Set the first LED */ hal_led_pin_set(BSP_LED_0, true); mesh_core_setup(); access_setup(); rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS); /* Adding custom data to flash for persistent storage */ // 1) Flash manager is already initialized // 2) Add a new flash manager instance. NB: should not overlap (in region) the instance used by mesh. flash_manager_config_t custom_data_manager_config; custom_data_manager_config.write_complete_cb = NULL; custom_data_manager_config.invalidate_complete_cb = NULL; custom_data_manager_config.remove_complete_cb = NULL; custom_data_manager_config.min_available_space = WORD_SIZE; // The new instance of flash manager should use an unused region of flash: custom_data_manager_config.p_area = (const flash_manager_page_t *) (((const uint8_t *) dsm_flash_area_get()) - (ACCESS_FLASH_PAGE_COUNT * PAGE_SIZE) - (NET_FLASH_PAGE_COUNT * PAGE_SIZE) ); custom_data_manager_config.page_count = CUSTOM_DATA_FLASH_PAGE_COUNT; ret_code = flash_manager_add(&m_custom_data_flash_manager, &custom_data_manager_config); if (NRF_SUCCESS != ret_code) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Flash error: no memory\n",ret_code); } // 3) Write to Flash // a) allocate flash fm_entry_t * p_entry = flash_manager_entry_alloc(&m_custom_data_flash_manager, FLASH_CUSTOM_DATA_GROUP_ELEMENT, sizeof(custom_data_format_t)); if (p_entry == NULL) { return NRF_ERROR_BUSY; } else { custom_data_format_t * p_custom_data = (custom_data_format_t *) p_entry->data; p_custom_data->data[0] = 5; p_custom_data->data[1] = 9; // b) write to flash flash_manager_entry_commit(p_entry); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "write:%x, %x\n",p_entry->data[0], p_entry->data[1]); } // 4) Wait for flash manager to finish. flash_manager_wait(); // 5) Read from Flash const fm_entry_t * p_read_raw = flash_manager_entry_get(&m_custom_data_flash_manager, FLASH_CUSTOM_DATA_GROUP_ELEMENT); const custom_data_format_t * p_read_data = (const custom_data_format_t *) p_read_raw->data; __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "read:%x, %x\n",p_read_data->data[0], p_read_data->data[1]); while (true) { (void)sd_app_evt_wait(); } }
this code work fine, but i didn't understand how it pick the address and where it put the address(which variable)? and how i pick and where i put address that i want? and how i know that the address that i pick it a "good" address?
thanks!