This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Adapting BLE Eddystone Beacon Example

Good day,

I wish to adapt the Eddystone Beacon example for nRF51822 with S130 in e.g.:

..\nRF5_SDK_12.3.0\examples\ble_peripheral\ble_app_beacon\pca10028\s130\armgcc

as follows:

1)  Configure slot 1 as TLM in the application code (retain slot 0 as default URL);

2)  Disable 'connectability' in the code (as per step 1 above, this will no longer be required);

3)  Increase period between transmissions

all in order to reduce power consumption.

Please provide information as to how/where to implement the above changes.

Thank you.

Regards

Jacques

Parents
  • Good day

    In my implementation I only use TLM frames, so I have no need for any other frames such as URL or UID.  When I implement what has been proposed here:

    https://devzone.nordicsemi.com/f/nordic-q-a/19421/configure-tlm-frame-type-by-default-in-eddystone-beacon---sdk-12-2-0

    in the BLE Eddystone Beacon Example, and do a full recompile, I get compile error copied at the bottom of the post.

    I am using SDK 12.3.0 + nRF51822 QFAAH1 + pca10028 + S130.

    I attached the two files that have been changed as per above-mentioned post:

    ...\nRF5_SDK_12.3.0\components\libraries\eddystone\es_slot.c
    ...\nRF5_SDK_12.3.0\examples\ble_peripheral\ble_app_eddystone\es_app_config.h

    /**
     * Copyright (c) 2016 - 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>
    #include "es_slot.h"
    #include "es_flash.h"
    #include "es_security.h"
    #include "es_slot_reg.h"
    #include "es_tlm.h"
    #include "fds.h"
    
    static es_slot_reg_t m_reg;             //!< Slot registry.
    static bool m_eid_loaded_from_flash;    //!< Set to true if EID slot has been loaded from flash.
    
    #define RANGING_DATA_INDEX  (1)         //!< Index of ranging data within frames that contain ranging data.
    #define RANGING_DATA_LENGTH (1)         //!< Length of ranging data.
    
    /**@brief Enforce legal slot number.
     *
     * @param[in] p_slot Pointer to the slot number variable to check.
     */
    static void slot_boundary_check(uint8_t * p_slot)
    {
        if (*p_slot > (APP_MAX_ADV_SLOTS - 1))
        {
            *p_slot = (APP_MAX_ADV_SLOTS - 1);
        }
    }
    
    
    /**@brief Function loading slot data from flash.
     *
     * @param[in] slot_no       Slot number to be used.
     */
    static void load_slot_from_flash(uint8_t slot_no)
    {
        ret_code_t err_code;
    
        err_code = es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_READ);
        if (err_code != FDS_ERR_NOT_FOUND)
        {
            APP_ERROR_CHECK(err_code);
    
            if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
            {
                m_eid_loaded_from_flash = true;
    
                es_security_eid_slots_restore(slot_no,
                                              m_reg.slots[slot_no].k_scaler,
                                              m_reg.slots[slot_no].seconds,
                                              (const uint8_t *)m_reg.slots[slot_no].ik);
            }
    
            else
            {
                // If a non-EID slot has been loaded, update the state of m_reg immediately.
                es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, m_reg.slots[slot_no].adv_frame.type, true);
            }
        }
    }
    
    
    /**@brief Function for setting the ranging data field to be broadcast in the frame.
     *
     * @param[in]       slot_no         The slot index.
     * @param[in]       tx_power        The radio tx power to be calibrated to ranging data.
     */
    static void set_ranging_data_for_slot(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t tx_power)
    {
        int8_t ranging_data_array[ESCS_NUM_OF_SUPPORTED_TX_POWER] = APP_CONFIG_CALIBRATED_RANGING_DATA;
        nrf_ble_escs_radio_tx_pwr_t supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER] =
            ESCS_SUPPORTED_TX_POWER;
    
        int8_t ranging_data = 0;
    
        if (m_reg.slots[slot_no].adv_custom_tx_power)
        {
            ranging_data = m_reg.slots[slot_no].custom_tx_power;
        }
    
        else
        {
            for (uint32_t i = 0; i < ESCS_NUM_OF_SUPPORTED_TX_POWER; ++i)
            {
                if (supported_tx[i] >= tx_power)
                {
                    ranging_data = ranging_data_array[i];
                    break;
                }
            }
        }
        es_adv_frame_t * frame = &m_reg.slots[slot_no].adv_frame;
        switch (frame->type)
        {
            case ES_FRAME_TYPE_UID:
            {
                es_uid_frame_t * uid = &frame->frame.uid;
                uid->ranging_data    = ranging_data;
                break;
            }
    
            case ES_FRAME_TYPE_URL:
            {
                es_url_frame_t * url = &frame->frame.url;
                url->ranging_data    = ranging_data;
                break;
            }
    
            case ES_FRAME_TYPE_EID:
            {
                es_eid_frame_t * eid = &frame->frame.eid;
                eid->ranging_data    = ranging_data;
                break;
            }
    
            case ES_FRAME_TYPE_TLM:
                APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
                break;
        }
    }
    
    
    /**@brief Function configuring a non-EID slot.
     *
     * @param[in] slot_no       Slot number to be used.
     * @param[in] length        Length of write operation.
     * @param[in] p_frame_data  Pointer to written data.
     */
    static void configure_slot(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
    {
        // If a TLM slot is being configured and there already exists a TLM.
        if ((es_frame_type_t)p_frame_data[0] == ES_FRAME_TYPE_TLM && m_reg.tlm_configured)
        {
            return; // Silently ignore any attempts to create more than one TLM slot as there is no point.
        }
    
        es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, (es_frame_type_t)p_frame_data[0], false);
    
        // For convenience, frame_type is stored in two places, set both.
        m_reg.slots[slot_no].adv_frame.type = (es_frame_type_t)p_frame_data[0];
        memcpy(&m_reg.slots[slot_no].adv_frame.frame, &m_reg.slots[slot_no].adv_frame.type, 1);
    
        uint8_t * p_data_after_ranging_data = ((uint8_t *)(&m_reg.slots[slot_no].adv_frame.frame) +
                                               RANGING_DATA_INDEX + RANGING_DATA_LENGTH);
    
        switch (m_reg.slots[slot_no].adv_frame.type)
        {
            case ES_FRAME_TYPE_UID:
            // Fall through.
            case ES_FRAME_TYPE_URL:
                memcpy(p_data_after_ranging_data, &p_frame_data[1], length);
                set_ranging_data_for_slot(slot_no, APP_CFG_DEFAULT_RADIO_TX_POWER);
                m_reg.slots[slot_no].adv_frame.length = length + 1; // + 1 for ranging data
                break;
    
            case ES_FRAME_TYPE_TLM:
                es_tlm_tlm_get(&m_reg.slots[slot_no].adv_frame.frame.tlm);
                m_reg.slots[slot_no].adv_frame.length = ES_TLM_LENGTH;
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function configuring an EID slot.
     *
     * @param[in] slot_no       Slot number to be used.
     * @param[in] length        Length of write operation.
     * @param[in] p_frame_data  Pointer to written data.
     */
    static void configure_eid_slot(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
    {
        bool clear_eid_slot = false;
    
        // Do not update slot count, as this will be done when in the callback invoked when the EID data
        // is ready.
        // As it takes a while to do the calculation, temporarily remove the slot being overwritten.
        // The slot will be re-added in the callback invoked when the EID data is ready.
        clear_eid_slot = es_slot_reg_clear_slot(&m_reg, slot_no);
    
        if (clear_eid_slot)
        {
            es_security_eid_slot_destroy(slot_no);
        }
    
        if (p_frame_data[0] != ES_FRAME_TYPE_EID)
        {
            APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
        }
    
        if (length == ESCS_EID_WRITE_ECDH_LENGTH)
        {
            es_security_client_pub_ecdh_receive(slot_no,
                                                &p_frame_data[ESCS_EID_WRITE_PUB_KEY_INDEX],
                                                p_frame_data[ESCS_EID_WRITE_ECDH_LENGTH -1]);
        }
    
        else if (length == ESCS_EID_WRITE_IDK_LENGTH)
        {
            es_security_shared_ik_receive(slot_no,
                                          &p_frame_data[ESCS_EID_WRITE_ENC_ID_KEY_INDEX],
                                          p_frame_data[ESCS_EID_WRITE_IDK_LENGTH - 1]);
        }
    
        else
        {
            // Invalid length being written.
            APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
        }
    }
    
    
    ret_code_t es_slot_write_to_flash(uint8_t slot_no)
    {
        if (m_reg.slots[slot_no].configured)
        {
            // If its an EID, we need to store some metadata in order to re-initialize the EID.
            if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
            {
                m_reg.slots[slot_no].seconds  = es_security_clock_get(slot_no);
                m_reg.slots[slot_no].k_scaler = es_security_scaler_get(slot_no);
                es_security_plain_eid_id_key_get(slot_no, m_reg.slots[slot_no].ik);
            }
            return es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_WRITE);
        }
    
        else
        {
            return es_flash_access_slot_configs(slot_no, NULL, ES_FLASH_ACCESS_CLEAR);
        }
    }
    
    
    void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr)
    {
        slot_boundary_check(&slot_no);
    
        m_reg.slots[slot_no].radio_tx_pwr = radio_tx_pwr;
    
        if (!m_reg.slots[slot_no].adv_custom_tx_power) // Only update TX power in ADV if custom TX power is not set
        {
            set_ranging_data_for_slot(slot_no, radio_tx_pwr);
        }
    }
    
    
    void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr)
    {
        slot_boundary_check(&slot_no);
    
        m_reg.slots[slot_no].adv_custom_tx_power = true;
        m_reg.slots[slot_no].custom_tx_power     = tx_pwr;
        set_ranging_data_for_slot(slot_no, tx_pwr);
    }
    
    
    void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
    {
        slot_boundary_check(&slot_no);
    
        if (p_frame_data == NULL)
        {
            APP_ERROR_CHECK(NRF_ERROR_NULL);
        }
    
        // Cleared
        if (length == 0 || (length == 1 && p_frame_data[0] == 0))
        {
            (void)es_slot_reg_clear_slot(&m_reg, slot_no);
        }
        // EID slot being configured
        else if (p_frame_data[0] == ES_FRAME_TYPE_EID &&
                 (length == ESCS_EID_WRITE_ECDH_LENGTH || length == ESCS_EID_WRITE_IDK_LENGTH))
        {
            if (m_reg.slots[slot_no].configured)
                (void)es_slot_reg_clear_slot(&m_reg, slot_no);
            configure_eid_slot(slot_no, length, p_frame_data);
        }
        // Non-EID slot configured.
        else
        {
            if (m_reg.slots[slot_no].configured)
                (void)es_slot_reg_clear_slot(&m_reg, slot_no);
            configure_slot(slot_no, length, p_frame_data);
        }
    }
    
    
    void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key)
    {
        slot_boundary_check(&slot_no);
        if (p_eid_id_key != NULL)
        {
            memcpy(&(m_reg.slots[slot_no].encrypted_eid_id_key), p_eid_id_key,
                   sizeof(nrf_ble_escs_eid_id_key_t));
        }
    }
    
    
    void es_slot_eid_ready(uint8_t slot_no)
    {
        m_reg.slots[slot_no].adv_frame.type   = ES_FRAME_TYPE_EID;
        m_reg.slots[slot_no].adv_frame.length = ES_EID_LENGTH;
        es_security_eid_get(slot_no, (uint8_t *)m_reg.slots[slot_no].adv_frame.frame.eid.eid);
        m_reg.slots[slot_no].adv_frame.frame.eid.frame_type = ES_FRAME_TYPE_EID;
        set_ranging_data_for_slot(slot_no, m_reg.slots[slot_no].radio_tx_pwr);
    
        if (m_eid_loaded_from_flash)
        {
            es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, true);
            m_eid_loaded_from_flash = false;
        }
    
        else
        {
            es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, false);
        }
    }
    
    
    static bool slot_is_eid(uint8_t eid_slot_no)
    {
        for (uint32_t i = 0; i < m_reg.num_configured_eid_slots; ++i)
        {
            if (m_reg.eid_slots_configured[i] == eid_slot_no)
            {
                return true;
            }
        }
    
        return false;
    }
    
    
    void es_slot_tlm_update(void)
    {
        if (m_reg.tlm_configured)
        {
            es_tlm_tlm_get(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.tlm);
        }
    }
    
    
    void es_slot_etlm_update(uint8_t eid_slot_no)
    {
        es_tlm_frame_t  tlm;
        es_etlm_frame_t etlm;
    
        // Ignore the request if eTLM is not required or slot no does not correspond to an EID slot.
        if (!es_slot_reg_etlm_required(&m_reg) || !slot_is_eid(eid_slot_no))
        {
            return;
        }
    
        es_tlm_tlm_get(&tlm);
    
        es_security_tlm_to_etlm(eid_slot_no, &tlm, &etlm);
    
        memcpy(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.etlm, &etlm, sizeof(es_etlm_frame_t));
        m_reg.slots[m_reg.tlm_slot].adv_frame.length = sizeof(es_etlm_frame_t);
    }
    
    
    const es_slot_reg_t * es_slot_get_registry(void)
    {
        return (const es_slot_reg_t *)&m_reg;
    }
    
    
    void es_slots_init(const es_slot_t * p_default_slot)
    {
        ret_code_t       err_code;
        es_flash_flags_t flash_flags = {{0}};
    
        es_slot_reg_init(&m_reg);
    
        m_eid_loaded_from_flash = false;
    
        // Read the flash flags to see if there are any previously stored slot configs
        err_code = es_flash_access_flags(&flash_flags, ES_FLASH_ACCESS_READ);
    
        if (err_code == FDS_ERR_NOT_FOUND)
        {
            // Factory reset or initial boot, load default data
            memcpy(&m_reg.slots[0], p_default_slot, sizeof(*p_default_slot));
            es_slot_reg_update_slot_list_info_on_add(&m_reg, 0, p_default_slot->adv_frame.type, true);
    		
    		#if APP_ENABLE_TLM_BY_DEFAULT == 1
    		es_slot_reg_update_slot_list_info_on_add(&m_reg, default_tlm_slot, ES_FRAME_TYPE_TLM, true);
    		m_reg.slots[default_tlm_slot].adv_frame.type = ES_FRAME_TYPE_TLM;
    		memcpy(&m_reg.slots[default_tlm_slot].adv_frame.frame, &m_reg.slots[default_tlm_slot].adv_frame.type, 1);
    		m_reg.slots[default_tlm_slot].adv_frame.length = ES_TLM_LENGTH;
    		#endif
    		
        }
    
        else
        {
            APP_ERROR_CHECK(err_code);
    
            for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
            {
                if (!flash_flags.slot_is_empty[i])
                {
                    load_slot_from_flash(i);
                }
            }
        }
    }
    
      es_app_config.h

    Make directory:
    ...\nRF5_SDK_12.3.0\examples\ble_peripheral\ble_app_eddystone\pca10028\s130\armgcc

    Thank you
    Regards
    Jacques

    ...
    Compiling file: es_slot.c
    ../../../../../../components/libraries/eddystone/es_slot.c: In function 'es_slots_init':
    ../../../../../../components/libraries/eddystone/es_slot.c:429:52: error: 'default_tlm_slot' undeclared (first use in this function); did you mean 'p_default_slot'?
    es_slot_reg_update_slot_list_info_on_add(&m_reg, default_tlm_slot, ES_FRAME_TYPE_TLM, true);
    ^~~~~~~~~~~~~~~~
    p_default_slot
    ../../../../../../components/libraries/eddystone/es_slot.c:429:52: note: each undeclared identifier is reported only once for each function it appears in
    make: *** [../../../../../../components/toolchain/gcc/Makefile.common:135: _build/nrf51422_xxac_es_slot.c.o] Error 1

Reply
  • Good day

    In my implementation I only use TLM frames, so I have no need for any other frames such as URL or UID.  When I implement what has been proposed here:

    https://devzone.nordicsemi.com/f/nordic-q-a/19421/configure-tlm-frame-type-by-default-in-eddystone-beacon---sdk-12-2-0

    in the BLE Eddystone Beacon Example, and do a full recompile, I get compile error copied at the bottom of the post.

    I am using SDK 12.3.0 + nRF51822 QFAAH1 + pca10028 + S130.

    I attached the two files that have been changed as per above-mentioned post:

    ...\nRF5_SDK_12.3.0\components\libraries\eddystone\es_slot.c
    ...\nRF5_SDK_12.3.0\examples\ble_peripheral\ble_app_eddystone\es_app_config.h

    /**
     * Copyright (c) 2016 - 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>
    #include "es_slot.h"
    #include "es_flash.h"
    #include "es_security.h"
    #include "es_slot_reg.h"
    #include "es_tlm.h"
    #include "fds.h"
    
    static es_slot_reg_t m_reg;             //!< Slot registry.
    static bool m_eid_loaded_from_flash;    //!< Set to true if EID slot has been loaded from flash.
    
    #define RANGING_DATA_INDEX  (1)         //!< Index of ranging data within frames that contain ranging data.
    #define RANGING_DATA_LENGTH (1)         //!< Length of ranging data.
    
    /**@brief Enforce legal slot number.
     *
     * @param[in] p_slot Pointer to the slot number variable to check.
     */
    static void slot_boundary_check(uint8_t * p_slot)
    {
        if (*p_slot > (APP_MAX_ADV_SLOTS - 1))
        {
            *p_slot = (APP_MAX_ADV_SLOTS - 1);
        }
    }
    
    
    /**@brief Function loading slot data from flash.
     *
     * @param[in] slot_no       Slot number to be used.
     */
    static void load_slot_from_flash(uint8_t slot_no)
    {
        ret_code_t err_code;
    
        err_code = es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_READ);
        if (err_code != FDS_ERR_NOT_FOUND)
        {
            APP_ERROR_CHECK(err_code);
    
            if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
            {
                m_eid_loaded_from_flash = true;
    
                es_security_eid_slots_restore(slot_no,
                                              m_reg.slots[slot_no].k_scaler,
                                              m_reg.slots[slot_no].seconds,
                                              (const uint8_t *)m_reg.slots[slot_no].ik);
            }
    
            else
            {
                // If a non-EID slot has been loaded, update the state of m_reg immediately.
                es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, m_reg.slots[slot_no].adv_frame.type, true);
            }
        }
    }
    
    
    /**@brief Function for setting the ranging data field to be broadcast in the frame.
     *
     * @param[in]       slot_no         The slot index.
     * @param[in]       tx_power        The radio tx power to be calibrated to ranging data.
     */
    static void set_ranging_data_for_slot(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t tx_power)
    {
        int8_t ranging_data_array[ESCS_NUM_OF_SUPPORTED_TX_POWER] = APP_CONFIG_CALIBRATED_RANGING_DATA;
        nrf_ble_escs_radio_tx_pwr_t supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER] =
            ESCS_SUPPORTED_TX_POWER;
    
        int8_t ranging_data = 0;
    
        if (m_reg.slots[slot_no].adv_custom_tx_power)
        {
            ranging_data = m_reg.slots[slot_no].custom_tx_power;
        }
    
        else
        {
            for (uint32_t i = 0; i < ESCS_NUM_OF_SUPPORTED_TX_POWER; ++i)
            {
                if (supported_tx[i] >= tx_power)
                {
                    ranging_data = ranging_data_array[i];
                    break;
                }
            }
        }
        es_adv_frame_t * frame = &m_reg.slots[slot_no].adv_frame;
        switch (frame->type)
        {
            case ES_FRAME_TYPE_UID:
            {
                es_uid_frame_t * uid = &frame->frame.uid;
                uid->ranging_data    = ranging_data;
                break;
            }
    
            case ES_FRAME_TYPE_URL:
            {
                es_url_frame_t * url = &frame->frame.url;
                url->ranging_data    = ranging_data;
                break;
            }
    
            case ES_FRAME_TYPE_EID:
            {
                es_eid_frame_t * eid = &frame->frame.eid;
                eid->ranging_data    = ranging_data;
                break;
            }
    
            case ES_FRAME_TYPE_TLM:
                APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
                break;
        }
    }
    
    
    /**@brief Function configuring a non-EID slot.
     *
     * @param[in] slot_no       Slot number to be used.
     * @param[in] length        Length of write operation.
     * @param[in] p_frame_data  Pointer to written data.
     */
    static void configure_slot(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
    {
        // If a TLM slot is being configured and there already exists a TLM.
        if ((es_frame_type_t)p_frame_data[0] == ES_FRAME_TYPE_TLM && m_reg.tlm_configured)
        {
            return; // Silently ignore any attempts to create more than one TLM slot as there is no point.
        }
    
        es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, (es_frame_type_t)p_frame_data[0], false);
    
        // For convenience, frame_type is stored in two places, set both.
        m_reg.slots[slot_no].adv_frame.type = (es_frame_type_t)p_frame_data[0];
        memcpy(&m_reg.slots[slot_no].adv_frame.frame, &m_reg.slots[slot_no].adv_frame.type, 1);
    
        uint8_t * p_data_after_ranging_data = ((uint8_t *)(&m_reg.slots[slot_no].adv_frame.frame) +
                                               RANGING_DATA_INDEX + RANGING_DATA_LENGTH);
    
        switch (m_reg.slots[slot_no].adv_frame.type)
        {
            case ES_FRAME_TYPE_UID:
            // Fall through.
            case ES_FRAME_TYPE_URL:
                memcpy(p_data_after_ranging_data, &p_frame_data[1], length);
                set_ranging_data_for_slot(slot_no, APP_CFG_DEFAULT_RADIO_TX_POWER);
                m_reg.slots[slot_no].adv_frame.length = length + 1; // + 1 for ranging data
                break;
    
            case ES_FRAME_TYPE_TLM:
                es_tlm_tlm_get(&m_reg.slots[slot_no].adv_frame.frame.tlm);
                m_reg.slots[slot_no].adv_frame.length = ES_TLM_LENGTH;
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function configuring an EID slot.
     *
     * @param[in] slot_no       Slot number to be used.
     * @param[in] length        Length of write operation.
     * @param[in] p_frame_data  Pointer to written data.
     */
    static void configure_eid_slot(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
    {
        bool clear_eid_slot = false;
    
        // Do not update slot count, as this will be done when in the callback invoked when the EID data
        // is ready.
        // As it takes a while to do the calculation, temporarily remove the slot being overwritten.
        // The slot will be re-added in the callback invoked when the EID data is ready.
        clear_eid_slot = es_slot_reg_clear_slot(&m_reg, slot_no);
    
        if (clear_eid_slot)
        {
            es_security_eid_slot_destroy(slot_no);
        }
    
        if (p_frame_data[0] != ES_FRAME_TYPE_EID)
        {
            APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
        }
    
        if (length == ESCS_EID_WRITE_ECDH_LENGTH)
        {
            es_security_client_pub_ecdh_receive(slot_no,
                                                &p_frame_data[ESCS_EID_WRITE_PUB_KEY_INDEX],
                                                p_frame_data[ESCS_EID_WRITE_ECDH_LENGTH -1]);
        }
    
        else if (length == ESCS_EID_WRITE_IDK_LENGTH)
        {
            es_security_shared_ik_receive(slot_no,
                                          &p_frame_data[ESCS_EID_WRITE_ENC_ID_KEY_INDEX],
                                          p_frame_data[ESCS_EID_WRITE_IDK_LENGTH - 1]);
        }
    
        else
        {
            // Invalid length being written.
            APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
        }
    }
    
    
    ret_code_t es_slot_write_to_flash(uint8_t slot_no)
    {
        if (m_reg.slots[slot_no].configured)
        {
            // If its an EID, we need to store some metadata in order to re-initialize the EID.
            if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
            {
                m_reg.slots[slot_no].seconds  = es_security_clock_get(slot_no);
                m_reg.slots[slot_no].k_scaler = es_security_scaler_get(slot_no);
                es_security_plain_eid_id_key_get(slot_no, m_reg.slots[slot_no].ik);
            }
            return es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_WRITE);
        }
    
        else
        {
            return es_flash_access_slot_configs(slot_no, NULL, ES_FLASH_ACCESS_CLEAR);
        }
    }
    
    
    void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr)
    {
        slot_boundary_check(&slot_no);
    
        m_reg.slots[slot_no].radio_tx_pwr = radio_tx_pwr;
    
        if (!m_reg.slots[slot_no].adv_custom_tx_power) // Only update TX power in ADV if custom TX power is not set
        {
            set_ranging_data_for_slot(slot_no, radio_tx_pwr);
        }
    }
    
    
    void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr)
    {
        slot_boundary_check(&slot_no);
    
        m_reg.slots[slot_no].adv_custom_tx_power = true;
        m_reg.slots[slot_no].custom_tx_power     = tx_pwr;
        set_ranging_data_for_slot(slot_no, tx_pwr);
    }
    
    
    void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t * p_frame_data)
    {
        slot_boundary_check(&slot_no);
    
        if (p_frame_data == NULL)
        {
            APP_ERROR_CHECK(NRF_ERROR_NULL);
        }
    
        // Cleared
        if (length == 0 || (length == 1 && p_frame_data[0] == 0))
        {
            (void)es_slot_reg_clear_slot(&m_reg, slot_no);
        }
        // EID slot being configured
        else if (p_frame_data[0] == ES_FRAME_TYPE_EID &&
                 (length == ESCS_EID_WRITE_ECDH_LENGTH || length == ESCS_EID_WRITE_IDK_LENGTH))
        {
            if (m_reg.slots[slot_no].configured)
                (void)es_slot_reg_clear_slot(&m_reg, slot_no);
            configure_eid_slot(slot_no, length, p_frame_data);
        }
        // Non-EID slot configured.
        else
        {
            if (m_reg.slots[slot_no].configured)
                (void)es_slot_reg_clear_slot(&m_reg, slot_no);
            configure_slot(slot_no, length, p_frame_data);
        }
    }
    
    
    void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key)
    {
        slot_boundary_check(&slot_no);
        if (p_eid_id_key != NULL)
        {
            memcpy(&(m_reg.slots[slot_no].encrypted_eid_id_key), p_eid_id_key,
                   sizeof(nrf_ble_escs_eid_id_key_t));
        }
    }
    
    
    void es_slot_eid_ready(uint8_t slot_no)
    {
        m_reg.slots[slot_no].adv_frame.type   = ES_FRAME_TYPE_EID;
        m_reg.slots[slot_no].adv_frame.length = ES_EID_LENGTH;
        es_security_eid_get(slot_no, (uint8_t *)m_reg.slots[slot_no].adv_frame.frame.eid.eid);
        m_reg.slots[slot_no].adv_frame.frame.eid.frame_type = ES_FRAME_TYPE_EID;
        set_ranging_data_for_slot(slot_no, m_reg.slots[slot_no].radio_tx_pwr);
    
        if (m_eid_loaded_from_flash)
        {
            es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, true);
            m_eid_loaded_from_flash = false;
        }
    
        else
        {
            es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, false);
        }
    }
    
    
    static bool slot_is_eid(uint8_t eid_slot_no)
    {
        for (uint32_t i = 0; i < m_reg.num_configured_eid_slots; ++i)
        {
            if (m_reg.eid_slots_configured[i] == eid_slot_no)
            {
                return true;
            }
        }
    
        return false;
    }
    
    
    void es_slot_tlm_update(void)
    {
        if (m_reg.tlm_configured)
        {
            es_tlm_tlm_get(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.tlm);
        }
    }
    
    
    void es_slot_etlm_update(uint8_t eid_slot_no)
    {
        es_tlm_frame_t  tlm;
        es_etlm_frame_t etlm;
    
        // Ignore the request if eTLM is not required or slot no does not correspond to an EID slot.
        if (!es_slot_reg_etlm_required(&m_reg) || !slot_is_eid(eid_slot_no))
        {
            return;
        }
    
        es_tlm_tlm_get(&tlm);
    
        es_security_tlm_to_etlm(eid_slot_no, &tlm, &etlm);
    
        memcpy(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.etlm, &etlm, sizeof(es_etlm_frame_t));
        m_reg.slots[m_reg.tlm_slot].adv_frame.length = sizeof(es_etlm_frame_t);
    }
    
    
    const es_slot_reg_t * es_slot_get_registry(void)
    {
        return (const es_slot_reg_t *)&m_reg;
    }
    
    
    void es_slots_init(const es_slot_t * p_default_slot)
    {
        ret_code_t       err_code;
        es_flash_flags_t flash_flags = {{0}};
    
        es_slot_reg_init(&m_reg);
    
        m_eid_loaded_from_flash = false;
    
        // Read the flash flags to see if there are any previously stored slot configs
        err_code = es_flash_access_flags(&flash_flags, ES_FLASH_ACCESS_READ);
    
        if (err_code == FDS_ERR_NOT_FOUND)
        {
            // Factory reset or initial boot, load default data
            memcpy(&m_reg.slots[0], p_default_slot, sizeof(*p_default_slot));
            es_slot_reg_update_slot_list_info_on_add(&m_reg, 0, p_default_slot->adv_frame.type, true);
    		
    		#if APP_ENABLE_TLM_BY_DEFAULT == 1
    		es_slot_reg_update_slot_list_info_on_add(&m_reg, default_tlm_slot, ES_FRAME_TYPE_TLM, true);
    		m_reg.slots[default_tlm_slot].adv_frame.type = ES_FRAME_TYPE_TLM;
    		memcpy(&m_reg.slots[default_tlm_slot].adv_frame.frame, &m_reg.slots[default_tlm_slot].adv_frame.type, 1);
    		m_reg.slots[default_tlm_slot].adv_frame.length = ES_TLM_LENGTH;
    		#endif
    		
        }
    
        else
        {
            APP_ERROR_CHECK(err_code);
    
            for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
            {
                if (!flash_flags.slot_is_empty[i])
                {
                    load_slot_from_flash(i);
                }
            }
        }
    }
    
      es_app_config.h

    Make directory:
    ...\nRF5_SDK_12.3.0\examples\ble_peripheral\ble_app_eddystone\pca10028\s130\armgcc

    Thank you
    Regards
    Jacques

    ...
    Compiling file: es_slot.c
    ../../../../../../components/libraries/eddystone/es_slot.c: In function 'es_slots_init':
    ../../../../../../components/libraries/eddystone/es_slot.c:429:52: error: 'default_tlm_slot' undeclared (first use in this function); did you mean 'p_default_slot'?
    es_slot_reg_update_slot_list_info_on_add(&m_reg, default_tlm_slot, ES_FRAME_TYPE_TLM, true);
    ^~~~~~~~~~~~~~~~
    p_default_slot
    ../../../../../../components/libraries/eddystone/es_slot.c:429:52: note: each undeclared identifier is reported only once for each function it appears in
    make: *** [../../../../../../components/toolchain/gcc/Makefile.common:135: _build/nrf51422_xxac_es_slot.c.o] Error 1

Children
  • Apologies, I notice that the post I referenced below requires the full code to be implemented in es_slot.c, not just the second section between the 2 pound symbols, i.e. copied at bottom of post.  I still get the compile error:

    Compiling file: es_slot.c
    ../../../../../../components/libraries/eddystone/es_slot.c: In function 'es_slots_init':
    ../../../../../../components/libraries/eddystone/es_slot.c:428:23: error: 'default_uid_slot' undeclared (first use in this function); did you mean 'p_default_slot'?
    memcpy(&m_reg.slots[default_uid_slot], p_default_slot, sizeof(*p_default_slot));
    ^~~~~~~~~~~~~~~~
    p_default_slot
    ../../../../../../components/libraries/eddystone/es_slot.c:428:23: note: each undeclared identifier is reported only once for each function it appears in
    ../../../../../../components/libraries/eddystone/es_slot.c:432:52: error: 'default_tlm_slot' undeclared (first use in this function); did you mean 'default_uid_slot'?
    es_slot_reg_update_slot_list_info_on_add(&m_reg, default_tlm_slot, ES_FRAME_TYPE_TLM, true);
    ^~~~~~~~~~~~~~~~
    default_uid_slot
    make: *** [../../../../../../components/toolchain/gcc/Makefile.common:135: _build/nrf51422_xxac_es_slot.c.o] Error 1

    Maybe its because I am using SDK 12.3.0 instead of 12.2.0?

    Thank you
    Regards
    Jacques

    if (err_code == FDS_ERR_NOT_FOUND)
    {
    // Factory reset or initial boot, load default data
    //memcpy(&m_reg.slots[0], p_default_slot, sizeof(*p_default_slot));
    //es_slot_reg_update_slot_list_info_on_add(&m_reg, 0, p_default_slot->adv_frame.type, true);

    memcpy(&m_reg.slots[default_uid_slot], p_default_slot, sizeof(*p_default_slot));
    es_slot_reg_update_slot_list_info_on_add(&m_reg, default_uid_slot, p_default_slot->adv_frame.type, true);

    #if APP_ENABLE_TLM_BY_DEFAULT == 1
    es_slot_reg_update_slot_list_info_on_add(&m_reg, default_tlm_slot, ES_FRAME_TYPE_TLM, true);
    m_reg.slots[default_tlm_slot].adv_frame.type = ES_FRAME_TYPE_TLM;
    memcpy(&m_reg.slots[default_tlm_slot].adv_frame.frame, &m_reg.slots[default_tlm_slot].adv_frame.type, 1);
    m_reg.slots[default_tlm_slot].adv_frame.length = ES_TLM_LENGTH;
    #endif

    }

  • Thank you Bjørn

    I downloaded the ZIP for 12.2.0 called DeviceDownload.zip, but Windows 8.1 fails to open it.

       

    I will retry download in the new year.

    All the best!

    Regards

    Jacques

  • Good day,

    Using Android app "nRF Beacon for Eddystone" I was able to reconfigure slot 0 from URL to TLM, so all good with that.  I was also able to set the Advertising Interval to 20 seconds.  What is the longest interval I can configure?  Also please confirm that during the quiet time in-between TLM adverts the SoC goes into deep sleep to conserve battery power?

    However, it seems to reject setting Tx Power to a lower value than 0dBm - I tried -12dBm, -16dBm and -20dBm but all of those cause Error 133 in the Android app.

    When I set slot 0 as URL and slot 1 as TLM, I can set -30dBm on slot 0.  This power is indicated in slot 0 (URL) but slot 1 (TLM) still shows 0dBm?  Does that mean slot 1 is transmitting at 0dBm and not -30dBm? EDIT: nRF Connect confirms URL is transmitted at -30dBm but TLM is transmitted at 0dBm.

    EDIT: I discovered that when I set only slot 0 to TLM (nothing in slot 1), with Adv. Interval set to 16384ms, the TLM transmissions was at 0dBm every 10-odd seconds.  For better battery life, I found it better to set slot 0 to URL (Adv. Interval=16384 and Radio Tx. Power=-30dBm) and slot 1 to TLM (Radio Tx. Power=0dBm).  As stated above, it would be more ideal to be able to also set TLM's Radio Tx. Power to -30dBm.

    Thank you
    Regards
    Jacques

Related