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

How to implement long press and short press for nrf5832(using 17.02 sdk and nrf5.0 sdk for mesh.... telling for reference) , i want to store scene when long press one button and recall scene when short press.

Hi,

 I want to store scene when long press one button and recall scene when short press. I have done some changes but not able to achieve it, i am not sure if i should use " bsp_event_to_button_action_assign" or "bsp_button_event_handler" for detecting long press and short press and then perform the scene store and scene recall operation.

I am attaching the implementation, correct me where i am wrong to achieve desired result. Can anyone help me in solving this issue on high priority?

in main.c

#include "bsp.h" // added for long and short press

#ifndef BSP_SIMPLE
static bsp_event_callback_t m_registered_callback = NULL;
static bsp_button_event_cfg_t m_events_list[BUTTONS_NUMBER] = {{BSP_EVENT_NOTHING, BSP_EVENT_NOTHING}};
APP_TIMER_DEF(m_bsp_button_tmr);
#endif // BSP_SIMPLE
#define BSP_LONG_PUSH_TIMEOUT_MS 1000

/ added for button long and short press

/**@brief Function for handling button events.
*
* @param[in] pin_no The pin number of the button pressed.
* @param[in] button_action Action button.
*/
static void bsp_button_event_handler(uint8_t pin_no, uint8_t button_action)
{
bsp_event_t event = BSP_EVENT_NOTHING;
uint32_t button = 0;
uint32_t err_code;
static uint8_t current_long_push_pin_no; /**< Pin number of a currently pushed button, that could become a long push if held long enough. */
static bsp_event_t release_event_at_push[BUTTONS_NUMBER]; /**< Array of what the release event of each button was last time it was pushed, so that no release event is sent if the event was bound after the push of the button. */


// added for scene

uint32_t status = NRF_SUCCESS;
static scene_store_params_t store_params = {.scene_number = 1 };
static scene_recall_params_t recall_params = {0};
static scene_delete_params_t delete_params = {0};

model_transition_t transition_params_scene =
{
.delay_ms = APP_SCENE_DELAY_MS,
.transition_time_ms = APP_SCENE_TRANSITION_TIME_MS
};

// recall_params.scene_number = store_params.scene_number;
delete_params.scene_number = store_params.scene_number;


// button = bsp_board_pin_to_button_idx(pin_no);

// if (button < BUTTONS_NUMBER)
// {
switch (button_action)
{
case APP_BUTTON_PUSH:
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO,"in bsp short press event handler button 4 pressed \n");
event = m_events_list[button].push_event;
if (m_events_list[button].long_push_event != BSP_EVENT_NOTHING)
{
// short press will recall the scene
//added for scene

// scene 1
/*
static scene_store_params_t store_params = {.scene_number = 1 };
static scene_recall_params_t recall_params = {0};
recall_params.scene_number = store_params.scene_number;
*/
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO,
"Sending msg: Scene Recall: Scene number: %d Tid: %d Trans time: %d ms Delay: %d ms\n",
recall_params.scene_number, recall_params.tid, transition_params_scene.transition_time_ms,
transition_params_scene.delay_ms);
status = scene_client_recall(&m_clients_scene[client], &recall_params, &transition_params_scene);
recall_params.tid++;

err_code = app_timer_start(m_bsp_button_tmr, APP_TIMER_TICKS(BSP_LONG_PUSH_TIMEOUT_MS), (void*)&current_long_push_pin_no);
if (err_code == NRF_SUCCESS)
{
current_long_push_pin_no = pin_no;
}
}
release_event_at_push[button] = m_events_list[button].release_event;
break;
case APP_BUTTON_RELEASE:
(void)app_timer_stop(m_bsp_button_tmr);
if (release_event_at_push[button] == m_events_list[button].release_event)
{
event = m_events_list[button].release_event;
}
break;
case BSP_BUTTON_ACTION_LONG_PUSH:

{
event = m_events_list[button].long_push_event;

// added for storing scene when long press
/*
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO,
"Sending msg: Scene Store: Scene number: %d\n", store_params.scene_number);
status = scene_client_store(&m_clients_scene[client], &store_params);

*/

}

}
//}
/*
if ((event != BSP_EVENT_NOTHING) && (m_registered_callback != NULL))
{
m_registered_callback(event);
}
*/
}

static void button_handler(uint_32 button_number)

{

case 4: 

bsp_button_event_handler(15,2);

}

Thanks & Regards,

Ekta

  • Hi Hung,

    1) What flag i should add in "call back m_button_handler_cb() " for long and short press, i am not able to understand this can you help me in making me understand.

    2) When i am pressing button it is always showing result for events that should happen in short press irrespective of fact that i am pressing it for long time. Is it like at first it is always short press then if we press it for long time it will go for long press, please help me in resolving this.

    Thanks & Regards,

    Ekta

  • Hi Hung,

    1) What flag i should add in "call back m_button_handler_cb() " for long and short press, i am not able to understand this can you help me in making me understand.

    2) When i am pressing button it is always showing result for events that should happen in short press irrespective of fact that i am pressing it for long time. Is it like at first it is always short press then if we press it for long time it will go for long press, please help me in resolving this.

    Thanks & Regards,

    Ekta

  • Hi, 

    Attached is my implementation. If you pressed the button for less than 2 seconds it will print out "short press", if you pressed the button for longer than 2 seconds it will show "long press"

    Note that you may need to deal with the corner case when the RTC counter wrap around. 

    Currently I only call same call back, but you can either add a flag or you define 2 different callback (2 different m_button_handler_cb() function) one for short  press and one for long press. 

    And note that this is applied for button with active low and it's only trigger when you release the button. So when the button go back to high, it will trigger the action. 

    3034.simple_hal.h

    /* Copyright (c) 2010 - 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 "simple_hal.h"
    #include "nrf_mesh_config_examples.h"
    #include "nrf_log.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include <stddef.h>
    #include "log.h"
    #include "nrf.h"
    #include "nrf_error.h"
    #include "boards.h"
    #include "nrf_delay.h"
    #include "nrf_log.h"
    #include "nrf_mesh_defines.h"
    #include "timer.h"
    #include "app_timer.h"
    #include "app_error.h"
    #include "nrfx_gpiote.h"
    #include "nrf_gpio.h"
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    
    #if BUTTON_BOARD
    static uint8_t m_buttons_list[BUTTONS_NUMBER] = BUTTONS_LIST;
    static timestamp_t m_last_button_press;
    static hal_button_handler_cb_t m_button_handler_cb;
    #endif
    
    #if SIMPLE_HAL_LEDS_ENABLED
    APP_TIMER_DEF(m_blink_timer);
    static uint32_t m_blink_count;
    static uint32_t m_blink_mask;
    static uint32_t m_prev_state;
    static const uint8_t m_leds_list[LEDS_NUMBER] = LEDS_LIST;
    #endif
    
    static void button_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_buttons_list); i++)
        {
            if (pin == m_buttons_list[i])
            {
                /* Check that the event was generated by a button press, and reject if it's too soon (debounce).
                 */
                  
                
                if (TIMER_DIFF(m_last_button_press, timer_now()) > HAL_BUTTON_PRESS_DEBOUNCE_INTERVAL)
                {
                    
                  if (nrf_gpio_pin_read(pin)==1)
                  {
                  
                      if (TIMER_DIFF(m_last_button_press, timer_now()) < HAL_BUTTON_PRESS_LONG_INTERVAL)
                      {
                          __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Short press \n");
                      }else
                      {
                          __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Long press \n");
                      }
                      m_button_handler_cb(i);
                  }
                 
                }
                m_last_button_press = timer_now();
            }
        }
    }
    
    static uint32_t hal_led_mask_state_get(uint32_t led_mask)
    {
        uint32_t state = 0;
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); ++i)
        {
            if (led_mask & (1 << i))
            {
                state = state | (hal_led_pin_get(m_leds_list[i]) << i);
            }
        }
        return state;
    }
    
    static void hal_led_mask_toggle(uint32_t led_mask)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            if (led_mask & (1 << i))
            {
                hal_led_pin_set(m_leds_list[i], !hal_led_pin_get(m_leds_list[i]));
            }
        }
    }
    
    /*****************************************************************************
     * Public API
     *****************************************************************************/
    
    #if SIMPLE_HAL_LEDS_ENABLED
    static void led_timeout_handler(void * p_context)
    {
        APP_ERROR_CHECK_BOOL(m_blink_count > 0);
        hal_led_mask_toggle(m_blink_mask);
    
        m_blink_count--;
        if (m_blink_count == 0)
        {
            (void) app_timer_stop(m_blink_timer);
            for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
            {
                if (m_blink_mask & (1 << i))
                {
                    hal_led_pin_set(m_leds_list[i], ((m_prev_state >> i) & 1));
                }
            }
        }
    }
    
    /** Returns @c true if the led at pin_no is on. */
    bool hal_led_pin_get(uint32_t pin)
    {
        /* If pin_no is set _low_ (0) the led is on. */
        return (nrf_gpio_pin_out_read(pin) == 0);
    }
    
    void hal_led_pin_set(uint32_t pin, bool value)
    {
        /* If pin_no is set _low_ (0) the led is on. */
        if (value)
        {
            nrfx_gpiote_out_clear(pin);
        }
        else
        {
            nrfx_gpiote_out_set(pin);
        }
    }
    
    void hal_led_mask_set(uint32_t led_mask, bool value)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            if (led_mask & (1 << i))
            {
                hal_led_pin_set(m_leds_list[i], value);
            }
        }
    }
    
    void hal_led_blink_ms(uint32_t led_mask, uint32_t delay_ms, uint32_t blink_count)
    {
        if (blink_count == 0 || delay_ms < HAL_LED_BLINK_PERIOD_MIN_MS)
        {
            return;
        }
    
        m_blink_mask  = led_mask;
        m_blink_count = blink_count * 2 - 1;
        m_prev_state = hal_led_mask_state_get(m_blink_mask);
    
        if (app_timer_start(m_blink_timer, APP_TIMER_TICKS(delay_ms), NULL) == NRF_SUCCESS)
        {
            /* Start by "clearing" the mask, i.e., turn the LEDs on -- in case a user calls the
             * function twice. */
            hal_led_mask_set(m_blink_mask, LED_MASK_STATE_ON);
        }
    }
    
    void hal_led_blink_stop(void)
    {
        (void) app_timer_stop(m_blink_timer);
        hal_led_mask_set(m_blink_mask, LED_MASK_STATE_OFF);
    }
    
    void hal_leds_init(void)
    {
        if (!nrfx_gpiote_is_init())
        {
            APP_ERROR_CHECK(nrfx_gpiote_init());
        }
        nrfx_gpiote_out_config_t out_config = {.init_state = NRF_GPIOTE_INITIAL_VALUE_HIGH, .task_pin = false};
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            APP_ERROR_CHECK(nrfx_gpiote_out_init(m_leds_list[i], &out_config));
        }
        APP_ERROR_CHECK(app_timer_create(&m_blink_timer, APP_TIMER_MODE_REPEATED, led_timeout_handler));
    }
    #endif /* SIMPLE_HAL_LEDS_ENABLED */
    
    uint32_t hal_buttons_init(hal_button_handler_cb_t cb)
    {
    #if !BUTTON_BOARD
        return NRF_ERROR_NOT_SUPPORTED;
    #else
        if (cb == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        if (GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS < BUTTONS_NUMBER)
        {
            return NRF_ERROR_NOT_SUPPORTED;
        }
        m_button_handler_cb = cb;
    
        if (!nrfx_gpiote_is_init())
        {
            APP_ERROR_CHECK(nrfx_gpiote_init());
        }
    
        nrfx_gpiote_in_config_t in_config = {
                                                .sense = NRF_GPIOTE_POLARITY_TOGGLE,
                                                .pull = BUTTON_PULL,
                                                .is_watcher = false,
                                                .hi_accuracy = false,
                                                .skip_gpio_setup = false
                                            };
        for (uint32_t i = 0; i < BUTTONS_NUMBER; ++i)
        {
            APP_ERROR_CHECK(nrfx_gpiote_in_init(m_buttons_list[i], &in_config, button_event_handler));
            nrfx_gpiote_in_event_enable(m_buttons_list[i], true);
        }
    
        return NRF_SUCCESS;
    #endif
    
    }
    

  • Hi Hung,

    Thank you for your inputs. Wanted to ask something:

    1) I have added one callback in the short press condition, is this the right way of doing it, if not then how it should be done, have inserted the code.

    2) I did not get when you said corner case of RTC counter wrap up. Can you please explain by its implementation.

    It will be very helpful if you can help me with this.

    /* Copyright (c) 2010 - 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 "simple_hal.h"
    #include "nrf_mesh_config_examples.h"
    #include "nrf_log.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include <stddef.h>
    #include "log.h"
    #include "nrf.h"
    #include "nrf_error.h"
    #include "boards.h"
    #include "nrf_delay.h"
    #include "nrf_log.h"
    #include "nrf_mesh_defines.h"
    #include "timer.h"
    #include "app_timer.h"
    #include "app_error.h"
    #include "nrfx_gpiote.h"
    #include "nrf_gpio.h"
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    
    #if BUTTON_BOARD
    static uint8_t m_buttons_list[BUTTONS_NUMBER] = BUTTONS_LIST;
    static timestamp_t m_last_button_press;
    static hal_button_handler_cb_t m_button_handler_cb;
    #endif
    
    #if SIMPLE_HAL_LEDS_ENABLED
    APP_TIMER_DEF(m_blink_timer);
    static uint32_t m_blink_count;
    static uint32_t m_blink_mask;
    static uint32_t m_prev_state;
    static const uint8_t m_leds_list[LEDS_NUMBER] = LEDS_LIST;
    #endif
    
    static void button_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_buttons_list); i++)
        {
            if (pin == m_buttons_list[i])
            {
                /* Check that the event was generated by a button press, and reject if it's too soon (debounce).
                 */
                  
                
                if (TIMER_DIFF(m_last_button_press, timer_now()) > HAL_BUTTON_PRESS_DEBOUNCE_INTERVAL)
                {
                    
                  if (nrf_gpio_pin_read(pin)==1)
                  {
                  
                      if (TIMER_DIFF(m_last_button_press, timer_now()) < HAL_BUTTON_PRESS_LONG_INTERVAL)
                      {
                          __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Short press \n");
                          m_button_handler_cb(i);  // added this callback
                      }else
                      {
                          __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Long press \n");
                      }
                      m_button_handler_cb(i);
                  }
                 
                }
                m_last_button_press = timer_now();
            }
        }
    }
    
    static uint32_t hal_led_mask_state_get(uint32_t led_mask)
    {
        uint32_t state = 0;
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); ++i)
        {
            if (led_mask & (1 << i))
            {
                state = state | (hal_led_pin_get(m_leds_list[i]) << i);
            }
        }
        return state;
    }
    
    static void hal_led_mask_toggle(uint32_t led_mask)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            if (led_mask & (1 << i))
            {
                hal_led_pin_set(m_leds_list[i], !hal_led_pin_get(m_leds_list[i]));
            }
        }
    }
    
    /*****************************************************************************
     * Public API
     *****************************************************************************/
    
    #if SIMPLE_HAL_LEDS_ENABLED
    static void led_timeout_handler(void * p_context)
    {
        APP_ERROR_CHECK_BOOL(m_blink_count > 0);
        hal_led_mask_toggle(m_blink_mask);
    
        m_blink_count--;
        if (m_blink_count == 0)
        {
            (void) app_timer_stop(m_blink_timer);
            for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
            {
                if (m_blink_mask & (1 << i))
                {
                    hal_led_pin_set(m_leds_list[i], ((m_prev_state >> i) & 1));
                }
            }
        }
    }
    
    /** Returns @c true if the led at pin_no is on. */
    bool hal_led_pin_get(uint32_t pin)
    {
        /* If pin_no is set _low_ (0) the led is on. */
        return (nrf_gpio_pin_out_read(pin) == 0);
    }
    
    void hal_led_pin_set(uint32_t pin, bool value)
    {
        /* If pin_no is set _low_ (0) the led is on. */
        if (value)
        {
            nrfx_gpiote_out_clear(pin);
        }
        else
        {
            nrfx_gpiote_out_set(pin);
        }
    }
    
    void hal_led_mask_set(uint32_t led_mask, bool value)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            if (led_mask & (1 << i))
            {
                hal_led_pin_set(m_leds_list[i], value);
            }
        }
    }
    
    void hal_led_blink_ms(uint32_t led_mask, uint32_t delay_ms, uint32_t blink_count)
    {
        if (blink_count == 0 || delay_ms < HAL_LED_BLINK_PERIOD_MIN_MS)
        {
            return;
        }
    
        m_blink_mask  = led_mask;
        m_blink_count = blink_count * 2 - 1;
        m_prev_state = hal_led_mask_state_get(m_blink_mask);
    
        if (app_timer_start(m_blink_timer, APP_TIMER_TICKS(delay_ms), NULL) == NRF_SUCCESS)
        {
            /* Start by "clearing" the mask, i.e., turn the LEDs on -- in case a user calls the
             * function twice. */
            hal_led_mask_set(m_blink_mask, LED_MASK_STATE_ON);
        }
    }
    
    void hal_led_blink_stop(void)
    {
        (void) app_timer_stop(m_blink_timer);
        hal_led_mask_set(m_blink_mask, LED_MASK_STATE_OFF);
    }
    
    void hal_leds_init(void)
    {
        if (!nrfx_gpiote_is_init())
        {
            APP_ERROR_CHECK(nrfx_gpiote_init());
        }
        nrfx_gpiote_out_config_t out_config = {.init_state = NRF_GPIOTE_INITIAL_VALUE_HIGH, .task_pin = false};
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            APP_ERROR_CHECK(nrfx_gpiote_out_init(m_leds_list[i], &out_config));
        }
        APP_ERROR_CHECK(app_timer_create(&m_blink_timer, APP_TIMER_MODE_REPEATED, led_timeout_handler));
    }
    #endif /* SIMPLE_HAL_LEDS_ENABLED */
    
    uint32_t hal_buttons_init(hal_button_handler_cb_t cb)
    {
    #if !BUTTON_BOARD
        return NRF_ERROR_NOT_SUPPORTED;
    #else
        if (cb == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        if (GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS < BUTTONS_NUMBER)
        {
            return NRF_ERROR_NOT_SUPPORTED;
        }
        m_button_handler_cb = cb;
    
        if (!nrfx_gpiote_is_init())
        {
            APP_ERROR_CHECK(nrfx_gpiote_init());
        }
    
        nrfx_gpiote_in_config_t in_config = {
                                                .sense = NRF_GPIOTE_POLARITY_TOGGLE,
                                                .pull = BUTTON_PULL,
                                                .is_watcher = false,
                                                .hi_accuracy = false,
                                                .skip_gpio_setup = false
                                            };
        for (uint32_t i = 0; i < BUTTONS_NUMBER; ++i)
        {
            APP_ERROR_CHECK(nrfx_gpiote_in_init(m_buttons_list[i], &in_config, button_event_handler));
            nrfx_gpiote_in_event_enable(m_buttons_list[i], true);
        }
    
        return NRF_SUCCESS;
    #endif
    
    }

    Thanks & Regards,

    Ekta

  • Hi Hung,

    Thank you for your inputs. Wanted to ask something:

    1) I have added one callback in the short press condition, is this the right way of doing it, if not then how it should be done, have inserted the code.

    2) I did not get when you said corner case of RTC counter wrap up. Can you please explain by its implementation.

    It will be very helpful if you can help me with this.

    /* Copyright (c) 2010 - 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 "simple_hal.h"
    #include "nrf_mesh_config_examples.h"
    #include "nrf_log.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include <stddef.h>
    #include "log.h"
    #include "nrf.h"
    #include "nrf_error.h"
    #include "boards.h"
    #include "nrf_delay.h"
    #include "nrf_log.h"
    #include "nrf_mesh_defines.h"
    #include "timer.h"
    #include "app_timer.h"
    #include "app_error.h"
    #include "nrfx_gpiote.h"
    #include "nrf_gpio.h"
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    
    #if BUTTON_BOARD
    static uint8_t m_buttons_list[BUTTONS_NUMBER] = BUTTONS_LIST;
    static timestamp_t m_last_button_press;
    static hal_button_handler_cb_t m_button_handler_cb;
    #endif
    
    #if SIMPLE_HAL_LEDS_ENABLED
    APP_TIMER_DEF(m_blink_timer);
    static uint32_t m_blink_count;
    static uint32_t m_blink_mask;
    static uint32_t m_prev_state;
    static const uint8_t m_leds_list[LEDS_NUMBER] = LEDS_LIST;
    #endif
    
    static void button_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_buttons_list); i++)
        {
            if (pin == m_buttons_list[i])
            {
                /* Check that the event was generated by a button press, and reject if it's too soon (debounce).
                 */
                  
                
                if (TIMER_DIFF(m_last_button_press, timer_now()) > HAL_BUTTON_PRESS_DEBOUNCE_INTERVAL)
                {
                    
                  if (nrf_gpio_pin_read(pin)==1)
                  {
                  
                      if (TIMER_DIFF(m_last_button_press, timer_now()) < HAL_BUTTON_PRESS_LONG_INTERVAL)
                      {
                          __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Short press \n");
                          m_button_handler_cb(i);  // added this callback
                      }else
                      {
                          __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Long press \n");
                      }
                      m_button_handler_cb(i);
                  }
                 
                }
                m_last_button_press = timer_now();
            }
        }
    }
    
    static uint32_t hal_led_mask_state_get(uint32_t led_mask)
    {
        uint32_t state = 0;
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); ++i)
        {
            if (led_mask & (1 << i))
            {
                state = state | (hal_led_pin_get(m_leds_list[i]) << i);
            }
        }
        return state;
    }
    
    static void hal_led_mask_toggle(uint32_t led_mask)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            if (led_mask & (1 << i))
            {
                hal_led_pin_set(m_leds_list[i], !hal_led_pin_get(m_leds_list[i]));
            }
        }
    }
    
    /*****************************************************************************
     * Public API
     *****************************************************************************/
    
    #if SIMPLE_HAL_LEDS_ENABLED
    static void led_timeout_handler(void * p_context)
    {
        APP_ERROR_CHECK_BOOL(m_blink_count > 0);
        hal_led_mask_toggle(m_blink_mask);
    
        m_blink_count--;
        if (m_blink_count == 0)
        {
            (void) app_timer_stop(m_blink_timer);
            for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
            {
                if (m_blink_mask & (1 << i))
                {
                    hal_led_pin_set(m_leds_list[i], ((m_prev_state >> i) & 1));
                }
            }
        }
    }
    
    /** Returns @c true if the led at pin_no is on. */
    bool hal_led_pin_get(uint32_t pin)
    {
        /* If pin_no is set _low_ (0) the led is on. */
        return (nrf_gpio_pin_out_read(pin) == 0);
    }
    
    void hal_led_pin_set(uint32_t pin, bool value)
    {
        /* If pin_no is set _low_ (0) the led is on. */
        if (value)
        {
            nrfx_gpiote_out_clear(pin);
        }
        else
        {
            nrfx_gpiote_out_set(pin);
        }
    }
    
    void hal_led_mask_set(uint32_t led_mask, bool value)
    {
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            if (led_mask & (1 << i))
            {
                hal_led_pin_set(m_leds_list[i], value);
            }
        }
    }
    
    void hal_led_blink_ms(uint32_t led_mask, uint32_t delay_ms, uint32_t blink_count)
    {
        if (blink_count == 0 || delay_ms < HAL_LED_BLINK_PERIOD_MIN_MS)
        {
            return;
        }
    
        m_blink_mask  = led_mask;
        m_blink_count = blink_count * 2 - 1;
        m_prev_state = hal_led_mask_state_get(m_blink_mask);
    
        if (app_timer_start(m_blink_timer, APP_TIMER_TICKS(delay_ms), NULL) == NRF_SUCCESS)
        {
            /* Start by "clearing" the mask, i.e., turn the LEDs on -- in case a user calls the
             * function twice. */
            hal_led_mask_set(m_blink_mask, LED_MASK_STATE_ON);
        }
    }
    
    void hal_led_blink_stop(void)
    {
        (void) app_timer_stop(m_blink_timer);
        hal_led_mask_set(m_blink_mask, LED_MASK_STATE_OFF);
    }
    
    void hal_leds_init(void)
    {
        if (!nrfx_gpiote_is_init())
        {
            APP_ERROR_CHECK(nrfx_gpiote_init());
        }
        nrfx_gpiote_out_config_t out_config = {.init_state = NRF_GPIOTE_INITIAL_VALUE_HIGH, .task_pin = false};
        for (uint32_t i = 0; i < ARRAY_SIZE(m_leds_list); i++)
        {
            APP_ERROR_CHECK(nrfx_gpiote_out_init(m_leds_list[i], &out_config));
        }
        APP_ERROR_CHECK(app_timer_create(&m_blink_timer, APP_TIMER_MODE_REPEATED, led_timeout_handler));
    }
    #endif /* SIMPLE_HAL_LEDS_ENABLED */
    
    uint32_t hal_buttons_init(hal_button_handler_cb_t cb)
    {
    #if !BUTTON_BOARD
        return NRF_ERROR_NOT_SUPPORTED;
    #else
        if (cb == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        if (GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS < BUTTONS_NUMBER)
        {
            return NRF_ERROR_NOT_SUPPORTED;
        }
        m_button_handler_cb = cb;
    
        if (!nrfx_gpiote_is_init())
        {
            APP_ERROR_CHECK(nrfx_gpiote_init());
        }
    
        nrfx_gpiote_in_config_t in_config = {
                                                .sense = NRF_GPIOTE_POLARITY_TOGGLE,
                                                .pull = BUTTON_PULL,
                                                .is_watcher = false,
                                                .hi_accuracy = false,
                                                .skip_gpio_setup = false
                                            };
        for (uint32_t i = 0; i < BUTTONS_NUMBER; ++i)
        {
            APP_ERROR_CHECK(nrfx_gpiote_in_init(m_buttons_list[i], &in_config, button_event_handler));
            nrfx_gpiote_in_event_enable(m_buttons_list[i], true);
        }
    
        return NRF_SUCCESS;
    #endif
    
    }

    Thanks & Regards,

    Ekta

Related