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

ANT+ sd_ant_channel_close reseting

Hi,

We are using nrf52832 for ANT and BLE for which we use SDK_17.0.2 and s332_nrf52_7.0.1

Our objective is to pair and un-pair ANT sensors. So far pairing multiple ANT sensors and snding the data via BLE works fine. But when we do try to un-pair sensors by closing the channel, the device does restarts.

For that we did try to use sd_ant_channel_close() function. We did use it in our event and in main while loop with a dalay as well. We did try with sd_ant_channel_unassign() function after closing the channel as well.

Is there some sequence that we are missing? Below is our channel init code. Thank you.

static void ANT_profile_HRM_setup(uint8_t ant_channel_no, uint32_t ant_device_no)
{
/** @snippet [ANT HRM RX Profile Setup] */
       
    uint32_t err_code = sd_ant_lib_config_set(ANT_LIB_CONFIG_MESG_OUT_INC_DEVICE_ID);
    APP_ERROR_CHECK(err_code);

        ant_channel_config_t channel_config =
    {
        .channel_number     = ant_channel_no,
        .channel_type       = CHANNEL_TYPE_SLAVE,
        .ext_assign         = HRM_EXT_ASSIGN,
        .rf_freq            = HRM_ANTPLUS_RF_FREQ,
        .transmission_type  = CHAN_ID_TRANS_TYPE,
        .device_type        = HRM_DEVICE_TYPE,
        .device_number      = ant_device_no,
        .channel_period     = HRM_MSG_PERIOD_1Hz,
        .network_number     = ANTPLUS_NETWORK_NUM,
    };

    const ant_search_config_t ant_search_config =
    {
        .channel_number        = ant_channel_no,
        .low_priority_timeout  = ANT_LOW_PRIORITY_TIMEOUT_DISABLE,
        .high_priority_timeout = ANT_HIGH_PRIORITY_SEARCH_DISABLE,
        .search_sharing_cycles = ANT_SEARCH_SHARING_CYCLES_DISABLE,
        .search_priority       = ANT_SEARCH_PRIORITY_DEFAULT,
        .waveform              = ANT_WAVEFORM_DEFAULT,
    };


    err_code = ant_hrm_disp_init(&m_ant_hrm, &channel_config, ant_tmp_evt_handler);
    APP_ERROR_CHECK(err_code);

        // Set search timeout
        err_code = ant_search_init(&ant_search_config);
        APP_ERROR_CHECK(err_code);

    err_code = sd_ant_channel_open(ant_channel_no);
    APP_ERROR_CHECK(err_code);


    err_code = ant_state_indicator_channel_opened();
    APP_ERROR_CHECK(err_code);

/** @snippet [ANT HRM RX Profile Setup] */
}

Best regards, Ram

Parents
  • But when we do try to un-pair sensors by closing the channel, the device does restarts.

    This means you likely have an assert, it will default do a soft reset if any api call return an error code. If you build with DEBUG (not RELEASE) then you should fint the actual error code, line number and file name causing the error in app_error_fault_handler(). Can you provide this information? 

    Thanks,
    Kenneth

  • Sorry, I should send that earlier.It stops in:

    nRF5_SDK_17.0.2_d674dde\components\libraries\log\src\nrf_log_frontend.c in line 999 (nrf_log_backend_enable(p_backend);)

    void nrf_log_panic(void)
    {
        nrf_log_backend_t const * p_backend = m_log_data.p_backend_head;
        m_log_data.autoflush = true;
        while (p_backend)
        {
            nrf_log_backend_enable(p_backend);
            nrf_log_backend_panic_set(p_backend);
            p_backend = p_backend->p_cb->p_next;
        }
    }

    Does that help?

  • Hi Kenneth;

    I was mising log_init() sorry. Ok now I have downloaded clean SDK_17.0.2 and s212_7.0.1 to make sure there isn't any of my code inside.

    - I have tested ANT HRM TX and RX example on 2 PCA10040 evaluation boards, and I do get the data over the serial terminal

    - I have added sd_ant_channel_close(HRM_CHANNEL_NUM); and it stops in HRM RX or TX example

    Code in main loop looks like:

    int main(void)
    {
        log_init();
        utils_setup();
        softdevice_setup();
        profile_setup();
    
        NRF_LOG_INFO("ANT+ Heart Rate RX example started.");
    
        for (;;)
        {
    
            if ( channel_flag_1 == 0)
            {
                ant_close_channel();
                channel_flag_1 = 1;
            }
    
            counter_1++;
    
    //        NRF_LOG_FLUSH();
    //        nrf_pwr_mgmt_run();
        }
    }

    ant_close_channel(); function is in ant_hrm.c just like other initialisations and contains only sd_ant_channel_close(HRM_CHANNEL_NUM);

    -This is only change in example code

    - In debug (not release) mode the code is running without restarting (before in my own code it did restart - because log_init() was missing I think)

    - It does pass ant_close_channel(); because 32-bit unsigned variable counter_1 does increase to around 9000. But then it stops. As well when trying it for few times, the counter variable is never exactly same value when it stops

    - When pressing pause in debugging it always stops in nrfx_uart.c and nrfx_uart.h (attached images), it looks like it is looping

    - After that I have commented NRF_LOG_FINAL_FLUSH() and set breakpoint at switch (id)

    - "id" variable is 0x00004002 so I do end up in NRF_FAULT_ID_SDK_ASSERT

    Is the sequence of how I am using sd_ant_channel_close incorrect?

  • Can you send me a modified nRF5 SDK example that I can run on an nRF52-DK, where the only change you do is to add sd_ant_channel_close() so I can see the example? I am very baffled that you are not getting a proper fault handler here.

    Kenneth

     

  • Hi Kenneth,

    yes of course. I am attaching(it is in HRM RX example):

    - complete SDK with example

    (nRF5_SDK_17.0.2_d674dde\examples\ant\ant_plus\ant_hrm\hrm_rx\pca10040\s212\ses)

    - ony main.c, ant_hrm.c, ant_hrm.h

    (\examples\ant\ant_plus\ant_hrm\hrm_rx          \components\ant\ant_profiles\ant_hrm)

    /**
     * This software is subject to the ANT+ Shared Source License
     * www.thisisant.com/swlicenses
     * Copyright (c) Garmin Canada Inc. 2012
     * 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 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 Garmin nor the names of its
     *       contributors may be used to endorse or promote products
     *       derived from this software without specific prior
     *       written permission.
     *
     * The following actions are prohibited:
     *
     *    1) Redistribution of source code containing the ANT+ Network
     *       Key. The ANT+ Network Key is available to ANT+ Adopters.
     *       Please refer to http://thisisant.com to become an ANT+
     *       Adopter and access the key. 
     *
     *    2) Reverse engineering, decompilation, and/or disassembly of
     *       software provided in binary form under this license.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
     * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
     * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE HEREBY
     * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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; DAMAGE TO ANY DEVICE, 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. SOME STATES DO NOT ALLOW 
     * THE EXCLUSION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE
     * ABOVE LIMITATIONS MAY NOT APPLY TO YOU.
     *
     */
    /**@file
     * @defgroup ant_hrm_rx_example ANT HRM RX example
     * @{
     * @ingroup nrf_ant_hrm
     *
     * @brief Example of ANT HRM RX profile.
     *
     * Before compiling this example for NRF52, complete the following steps:
     * - Download the S212 SoftDevice from <a href="https://www.thisisant.com/developer/components/nrf52832" target="_blank">thisisant.com</a>.
     * - Extract the downloaded zip file and copy the S212 SoftDevice headers to <tt>\<InstallFolder\>/components/softdevice/s212/headers</tt>.
     * If you are using Keil packs, copy the files into a @c headers folder in your example folder.
     * - Make sure that @ref ANT_LICENSE_KEY in @c nrf_sdm.h is uncommented.
     */
    
    #include <stdio.h>
    #include "nrf.h"
    #include "bsp.h"
    #include "hardfault.h"
    #include "app_error.h"
    #include "app_timer.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ant.h"
    #include "ant_key_manager.h"
    #include "ant_hrm.h"
    #include "bsp_btn_ant.h"
    #include "ant_state_indicator.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    // There are 7 lines added or commented out, in main.c #1-#5, in ant_hrm.c #6 and ant_hrm.h #7 they are all marked with #x 
    
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
    //#include "nrf_delay.h"
    //#include "ant_hrm.h"
    //#include "ant_interface.h"
    uint32_t counter_1 = 0;     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #1
    char channel_flag_1 = 0;    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #2
    
    /** @snippet [ANT HRM RX Instance] */
    HRM_DISP_CHANNEL_CONFIG_DEF(m_ant_hrm,
                                HRM_CHANNEL_NUM,
                                CHAN_ID_TRANS_TYPE,
                                CHAN_ID_DEV_NUM,
                                ANTPLUS_NETWORK_NUM,
                                HRM_MSG_PERIOD_4Hz);
    
    static ant_hrm_profile_t m_ant_hrm;
    /** @snippet [ANT HRM RX Instance] */
    
    
    NRF_SDH_ANT_OBSERVER(m_ant_observer, ANT_HRM_ANT_OBSERVER_PRIO,
                         ant_hrm_disp_evt_handler, &m_ant_hrm);
    
    static void ant_hrm_evt_handler(ant_hrm_profile_t * p_profile, ant_hrm_evt_t event)
    {
        nrf_pwr_mgmt_feed();
    
        switch (event)
        {
            case ANT_HRM_PAGE_0_UPDATED:
                /* fall through */
            case ANT_HRM_PAGE_1_UPDATED:
                /* fall through */
            case ANT_HRM_PAGE_2_UPDATED:
                /* fall through */
            case ANT_HRM_PAGE_3_UPDATED:
                /* fall through */
            case ANT_HRM_PAGE_4_UPDATED:
                NRF_LOG_INFO("Page was updated");
                break;
    
            default:
                break;
        }
    }
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in]   event   Event generated by BSP.
     */
    void bsp_event_handler(bsp_event_t event)
    {
        switch (event)
        {
            case BSP_EVENT_SLEEP:
                nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
                break;
    
            default:
                break;
        }
    }
    
    /**
     * @brief Function for shutdown events.
     *
     * @param[in]   event       Shutdown type.
     */
    static bool shutdown_handler(nrf_pwr_mgmt_evt_t event)
    {
        ret_code_t err_code;
    
        switch (event)
        {
            case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
                err_code = bsp_btn_ant_sleep_mode_prepare();
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                break;
        }
    
        return true;
    }
    
    NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, APP_SHUTDOWN_HANDLER_PRIORITY);
    
    /**@brief Function for the Timer and BSP initialization.
     */
    static void utils_setup(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS,
                            bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ant_init(m_ant_hrm.channel_number, HRM_DISP_CHANNEL_TYPE);
        APP_ERROR_CHECK(err_code);
    
        err_code = ant_state_indicator_init(m_ant_hrm.channel_number, HRM_DISP_CHANNEL_TYPE);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for ANT stack initialization.
     *
     * @details Initializes the SoftDevice and the ANT event interrupt.
     */
    static void softdevice_setup(void)
    {
        ret_code_t err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        ASSERT(nrf_sdh_is_enabled());
    
        err_code = nrf_sdh_ant_enable();
        APP_ERROR_CHECK(err_code);
    
        err_code = ant_plus_key_set(ANTPLUS_NETWORK_NUM);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for HRM profile initialization.
     *
     * @details Initializes the HRM profile and open ANT channel.
     */
    static void profile_setup(void)
    {
    /** @snippet [ANT HRM RX Profile Setup] */
        ret_code_t err_code =
            ant_hrm_disp_init(&m_ant_hrm, HRM_DISP_CHANNEL_CONFIG(m_ant_hrm), ant_hrm_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = ant_hrm_disp_open(&m_ant_hrm);
        APP_ERROR_CHECK(err_code);
    
        err_code = ant_state_indicator_channel_opened();
        APP_ERROR_CHECK(err_code);
    /** @snippet [ANT HRM RX Profile Setup] */
    }
    
    /**
     *@brief Function for initializing logging.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    /**@brief Function for application main entry, does not return.
     */
    int main(void)
    {
        log_init();
        utils_setup();
        softdevice_setup();
        profile_setup();
    
        NRF_LOG_INFO("ANT+ Heart Rate RX example started.");
    
        for (;;)
        {
    
            if ( channel_flag_1 == 0)       //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #3
            {
                ant_close_channel();
    //            sd_ant_channel_close(HRM_CHANNEL_NUM);
                channel_flag_1 = 1;
            }
    
            counter_1++;                  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #4
    
    //        NRF_LOG_FLUSH();            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #5 (commented out)
    //        nrf_pwr_mgmt_run();
        }
    }
    
    
    /**
     *@}
     **/
    
    /**
     * Copyright (c) 2015 - 2020, 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 "sdk_config.h"
    #if ANT_HRM_ENABLED
    
    #include "nrf_assert.h"
    #include "app_error.h"
    #include "ant_interface.h"
    #include "app_util.h"
    #include "ant_hrm.h"
    #include "ant_hrm_utils.h"
    #include "app_error.h"
    
    #define NRF_LOG_MODULE_NAME ant_hrm
    #if ANT_HRM_LOG_ENABLED
    #define NRF_LOG_LEVEL       ANT_HRM_LOG_LEVEL
    #define NRF_LOG_INFO_COLOR  ANT_HRM_INFO_COLOR
    #else // ANT_HRM_LOG_ENABLED
    #define NRF_LOG_LEVEL       0
    #endif // ANT_HRM_LOG_ENABLED
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    #define BACKGROUND_DATA_INTERVAL 64 /**< The number of main data pages sent between background data page.
                                             Background data page is sent every 65th message. */
    #define TX_TOGGLE_DIVISOR        4  /**< The number of messages between changing state of toggle bit. */
    
    /**@brief HRM message data layout structure. */
    typedef struct
    {
        ant_hrm_page_t page_number         : 7;
        uint8_t        toggle_bit          : 1;
        uint8_t        page_payload[7];
    } ant_hrm_message_layout_t;
    
    /**@brief Function for initializing the ANT HRM profile instance.
     *
     * @param[in]  p_profile        Pointer to the profile instance.
     * @param[in]  p_channel_config Pointer to the ANT channel configuration structure.
     *
     * @retval     NRF_SUCCESS      If initialization was successful. Otherwise, an error code is returned.
     */
    static ret_code_t ant_hrm_init(ant_hrm_profile_t          * p_profile,
                                 ant_channel_config_t const * p_channel_config)
    {
        p_profile->channel_number = p_channel_config->channel_number;
    
        p_profile->page_0 = DEFAULT_ANT_HRM_PAGE0();
        p_profile->page_1 = DEFAULT_ANT_HRM_PAGE1();
        p_profile->page_2 = DEFAULT_ANT_HRM_PAGE2();
        p_profile->page_3 = DEFAULT_ANT_HRM_PAGE3();
        p_profile->page_4 = DEFAULT_ANT_HRM_PAGE4();
    
        NRF_LOG_INFO("ANT HRM channel %u init", p_profile->channel_number);
        return ant_channel_init(p_channel_config);
    }
    
    
    ret_code_t ant_hrm_disp_init(ant_hrm_profile_t          * p_profile,
                               ant_channel_config_t const * p_channel_config,
                               ant_hrm_evt_handler_t        evt_handler)
    {
        ASSERT(p_profile != NULL);
        ASSERT(p_channel_config != NULL);
        ASSERT(evt_handler != NULL);
    
        p_profile->evt_handler = evt_handler;
    
        return ant_hrm_init(p_profile, p_channel_config);
    }
    
    
    ret_code_t ant_hrm_sens_init(ant_hrm_profile_t           * p_profile,
                               ant_channel_config_t const  * p_channel_config,
                               ant_hrm_sens_config_t const * p_sens_config)
    {
        ASSERT(p_profile != NULL);
        ASSERT(p_channel_config != NULL);
        ASSERT(p_sens_config != NULL);
        ASSERT(p_sens_config->p_cb != NULL);
        ASSERT(p_sens_config->evt_handler != NULL);
    
        ASSERT((p_sens_config->main_page_number == ANT_HRM_PAGE_0)
               || (p_sens_config->main_page_number == ANT_HRM_PAGE_4));
    
        p_profile->evt_handler       = p_sens_config->evt_handler;
        p_profile->_cb.p_sens_cb     = p_sens_config->p_cb;
    
        ant_hrm_sens_cb_t * p_hrm_cb = p_profile->_cb.p_sens_cb;
        p_hrm_cb->page_1_present     = p_sens_config->page_1_present;
        p_hrm_cb->main_page_number   = p_sens_config->main_page_number;
        p_hrm_cb->ext_page_number    = p_hrm_cb->page_1_present ? ANT_HRM_PAGE_1 : ANT_HRM_PAGE_2;
        p_hrm_cb->message_counter    = 0;
        p_hrm_cb->toggle_bit         = true;
    
        return ant_hrm_init(p_profile, p_channel_config);
    }
    
    
    /**@brief Function for getting next page number to send.
     *
     * @param[in]  p_profile        Pointer to the profile instance.
     *
     * @return     Next page number.
     */
    static ant_hrm_page_t next_page_number_get(ant_hrm_profile_t * p_profile)
    {
        ant_hrm_sens_cb_t * p_hrm_cb = p_profile->_cb.p_sens_cb;
        ant_hrm_page_t      page_number;
    
        if (p_hrm_cb->message_counter == (BACKGROUND_DATA_INTERVAL))
        {
            page_number = p_hrm_cb->ext_page_number;
    
            p_hrm_cb->message_counter = 0;
    
            p_hrm_cb->ext_page_number++;
    
            if (p_hrm_cb->ext_page_number > ANT_HRM_PAGE_3)
            {
                p_hrm_cb->ext_page_number = p_hrm_cb->page_1_present ? ANT_HRM_PAGE_1 : ANT_HRM_PAGE_2;
            }
        }
        else
        {
            page_number = p_hrm_cb->main_page_number;
        }
    
        if (p_hrm_cb->message_counter % TX_TOGGLE_DIVISOR == 0)
        {
            p_hrm_cb->toggle_bit ^= 1;
        }
    
        p_hrm_cb->message_counter++;
    
        return page_number;
    }
    
    
    /**@brief Function for encoding HRM message.
     *
     * @note Assume to be call each time when Tx window will occur.
     */
    static void sens_message_encode(ant_hrm_profile_t * p_profile, uint8_t * p_message_payload)
    {
        ant_hrm_message_layout_t * p_hrm_message_payload =
            (ant_hrm_message_layout_t *)p_message_payload;
        ant_hrm_sens_cb_t * p_hrm_cb = p_profile->_cb.p_sens_cb;
    
        p_hrm_message_payload->page_number = next_page_number_get(p_profile);
        p_hrm_message_payload->toggle_bit  = p_hrm_cb->toggle_bit;
    
        NRF_LOG_INFO("HRM TX Page number: %u", p_hrm_message_payload->page_number);
    
        ant_hrm_page_0_encode(p_hrm_message_payload->page_payload, &(p_profile->page_0)); // Page 0 is present in each message
    
        switch (p_hrm_message_payload->page_number)
        {
            case ANT_HRM_PAGE_0:
                // No implementation needed
                break;
    
            case ANT_HRM_PAGE_1:
                ant_hrm_page_1_encode(p_hrm_message_payload->page_payload, &(p_profile->page_1));
                break;
    
            case ANT_HRM_PAGE_2:
                ant_hrm_page_2_encode(p_hrm_message_payload->page_payload, &(p_profile->page_2));
                break;
    
            case ANT_HRM_PAGE_3:
                ant_hrm_page_3_encode(p_hrm_message_payload->page_payload, &(p_profile->page_3));
                break;
    
            case ANT_HRM_PAGE_4:
                ant_hrm_page_4_encode(p_hrm_message_payload->page_payload, &(p_profile->page_4));
                break;
    
            default:
                return;
        }
    
        p_profile->evt_handler(p_profile, (ant_hrm_evt_t)p_hrm_message_payload->page_number);
    }
    
    
    /**@brief Function for setting payload for ANT message and sending it.
     *
     * @param[in]  p_profile        Pointer to the profile instance.
     */
    static void ant_message_send(ant_hrm_profile_t * p_profile)
    {
        uint32_t err_code;
        uint8_t  p_message_payload[ANT_STANDARD_DATA_PAYLOAD_SIZE];
    
        sens_message_encode(p_profile, p_message_payload);
        err_code =
            sd_ant_broadcast_message_tx(p_profile->channel_number,
                                        sizeof (p_message_payload),
                                        p_message_payload);
        APP_ERROR_CHECK(err_code);
    }
    
    
    void ant_hrm_sens_evt_handler(ant_evt_t * p_ant_evt, void * p_context)
    {
        ant_hrm_profile_t * p_profile = (ant_hrm_profile_t *)p_context;
        if (p_ant_evt->channel == p_profile->channel_number)
        {
            switch (p_ant_evt->event)
            {
                case EVENT_TX:
                    ant_message_send(p_profile);
                    break;
    
                default:
                    break;
            }
        }
    }
    
    
    ret_code_t ant_hrm_disp_open(ant_hrm_profile_t * p_profile)
    {
        ASSERT(p_profile != NULL);
    
        NRF_LOG_INFO("ANT HRM channel %u open", p_profile->channel_number);
        return sd_ant_channel_open(p_profile->channel_number);
    }
    
    
    ret_code_t ant_hrm_sens_open(ant_hrm_profile_t * p_profile)
    {
        ASSERT(p_profile != NULL);
    
        // Fill tx buffer for the first frame
        ant_message_send(p_profile);
    
        NRF_LOG_INFO("ANT HRM channel %u open", p_profile->channel_number);
        return sd_ant_channel_open(p_profile->channel_number);
    }
    
    
    /**@brief Function for decoding HRM message.
     *
     * @note Assume to be call each time when Rx window will occur.
     */
    static void disp_message_decode(ant_hrm_profile_t * p_profile, uint8_t * p_message_payload)
    {
        const ant_hrm_message_layout_t * p_hrm_message_payload =
            (ant_hrm_message_layout_t *)p_message_payload;
    
        NRF_LOG_INFO("HRM RX Page Number: %u", p_hrm_message_payload->page_number);
    
        ant_hrm_page_0_decode(p_hrm_message_payload->page_payload, &(p_profile->page_0)); // Page 0 is present in each message
    
        switch (p_hrm_message_payload->page_number)
        {
            case ANT_HRM_PAGE_0:
                // No implementation needed
                break;
    
            case ANT_HRM_PAGE_1:
                ant_hrm_page_1_decode(p_hrm_message_payload->page_payload, &(p_profile->page_1));
                break;
    
            case ANT_HRM_PAGE_2:
                ant_hrm_page_2_decode(p_hrm_message_payload->page_payload, &(p_profile->page_2));
                break;
    
            case ANT_HRM_PAGE_3:
                ant_hrm_page_3_decode(p_hrm_message_payload->page_payload, &(p_profile->page_3));
                break;
    
            case ANT_HRM_PAGE_4:
                ant_hrm_page_4_decode(p_hrm_message_payload->page_payload, &(p_profile->page_4));
                break;
    
            default:
                return;
        }
    
        p_profile->evt_handler(p_profile, (ant_hrm_evt_t)p_hrm_message_payload->page_number);
    }
    
    
    void ant_hrm_disp_evt_handler(ant_evt_t * p_ant_evt, void * p_context)
    {
        ant_hrm_profile_t * p_profile = ( ant_hrm_profile_t *)p_context;
        if (p_ant_evt->channel == p_profile->channel_number)
        {
            switch (p_ant_evt->event)
            {
                case EVENT_RX:
                    if (p_ant_evt->message.ANT_MESSAGE_ucMesgID == MESG_BROADCAST_DATA_ID
                     || p_ant_evt->message.ANT_MESSAGE_ucMesgID == MESG_ACKNOWLEDGED_DATA_ID
                     || p_ant_evt->message.ANT_MESSAGE_ucMesgID == MESG_BURST_DATA_ID)
                    {
                        disp_message_decode(p_profile, p_ant_evt->message.ANT_MESSAGE_aucPayload);
                    }
                    break;
    
                default:
                    break;
            }
        }
    }
    
    void ant_close_channel(void)        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #6
    {
        sd_ant_channel_close(HRM_CHANNEL_NUM);
    }
    
    
    #endif // ANT_HRM_ENABLED
    
    ant_hrm.h

  • It seems to run fine here, what do you expect should happen if I run the HRM RX example project with your additional ant_close_channel()?

Reply Children
  • In a debug mode.

    It does stop because of some error. Please have a look at the video, 1. with ant_channel_close() counter stops and in video 2. when comentig out that function it counts normaly.

  • I believe this is because when the channel is closed it will go to system OFF mode, see ant_evt_handler() in ant_state_indicator.c where the switch case EVENT_CHANNEL_CLOSED will call nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);

    Edit: Please comment out this line if you don't want to go to system OFF.

    Kenneth

Related