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 Ekta, 

    It's hard for us to support you if you don't have an overview of how things work in our SDK. 

    1. In your code that you added the function, if you want to detect the short press and long press if you call the same function ? 
    You need to add another call back function, so that you have two call back function one for short press and one for long press. For example m_button_handler_short_cb and m_button_handler_long_cb. 
    You need to assign 2 difference functions in main.c to each of that to handle the short press and long press. 

    2. The RTC counter is a 24 bit register, so it will wrap around after it counted until 0xFFFFFF (it will become 0x00 after this overflow) this will cause TIMER_DIFF(m_last_button_press, timer_now()) result in incorrect timediff. You may need to handle this manually. The overflow happens every 2^24/32768 =  512 seconds. 

  • Hi Hung,

    I am new to this board and all functionalities so taking time to develop.Thank you for your responses.

    1) In file "simple_hal.c" i have inserted these changes :

    Is this the right way to do this?

    /** Acceptable button press interval in microseconds. */
    #define HAL_BUTTON_PRESS_DEBOUNCE_INTERVAL  MS_TO_US(400)
    
    #define HAL_BUTTON_PRESS_LONG_PRESS_INTERVAL MS_TO_US (5000)  // added for long and short press for 5 sec in simple_hal.h
    
    
    
    
    
    #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;
    
    static hal_button_handler_cb_t m_button_handler_long_cb;
    static hal_button_handler_cb_t m_button_handler_short_cb;
    
       
    static void button_handler_long_press(uint32_t button_number);
    static void button_handler_short_press(uint32_t button_number);
    #endif
    
    
    
    
    
    
    // added for long and short press
    static void button_handler_long_press(uint32_t button_number)
    {
         uint32_t status = NRF_SUCCESS;
         static uint8_t client = 0;
        
         // added for scene control
       static scene_client_t         m_clients_scene[CLIENT_MODEL_INSTANCE_COUNT];
       static bool                   m_device_provisioned;
    
        model_transition_t transition_params_scene = 
        {
          .delay_ms = APP_SCENE_DELAY_MS,
          .transition_time_ms = APP_SCENE_TRANSITION_TIME_MS
        };
         
        //  added for scene
        static scene_store_params_t store_params = {.scene_number = 0 };
        static scene_recall_params_t recall_params = {0};
        static scene_delete_params_t delete_params = {0};
       
        recall_params.scene_number = store_params.scene_number;
        delete_params.scene_number = store_params.scene_number;
    
     
               //added for storing scene for 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);
           //m_last_button_press = timer_now();
           m_button_handler_long_cb (button_number);
           //   button_long_callback(m_button_handler_long_cb , button_number);
    
    }
    
    static void button_handler_short_press(uint32_t button_number)
    {
    
        uint32_t status = NRF_SUCCESS;
        static uint8_t client = 0;
        
         // added for scene control
      static scene_client_t         m_clients_scene[CLIENT_MODEL_INSTANCE_COUNT];
      static bool                   m_device_provisioned;
    
      model_transition_t transition_params_scene = 
      {
        .delay_ms = APP_SCENE_DELAY_MS,
        .transition_time_ms = APP_SCENE_TRANSITION_TIME_MS
       };
      
      //  added for scene
       static scene_store_params_t store_params = {.scene_number = 0 };
       static scene_recall_params_t recall_params = {0};
       static scene_delete_params_t delete_params = {0};
       
       recall_params.scene_number = store_params.scene_number;
       delete_params.scene_number = store_params.scene_number;
    
             
              //added for recalling scene for short press
        __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++;
             //m_last_button_press = timer_now();
            m_button_handler_short_cb (button_number);
             // button_short_callback(m_button_handler_short_cb , button_number);
    }
    
    
    
    
    static void button_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    { 
    
          uint32_t status = NRF_SUCCESS;
          static uint8_t client = 0;
        
         // added for scene control
         static scene_client_t         m_clients_scene[CLIENT_MODEL_INSTANCE_COUNT];
         static bool                   m_device_provisioned;
    
        model_transition_t transition_params_scene = 
        {
            .delay_ms = APP_SCENE_DELAY_MS,
            .transition_time_ms = APP_SCENE_TRANSITION_TIME_MS
        };
    
        //  added for scene
       
        static scene_store_params_t store_params = {.scene_number = 0 };
        static scene_recall_params_t recall_params = {0};
        static scene_delete_params_t delete_params = {0};
       
        recall_params.scene_number = store_params.scene_number;
        delete_params.scene_number = store_params.scene_number;
    
    
        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 (pin == 18 ) // checking pin 18 for button 7  and pin 15 for button 4 in custom_board.h while in pca10040.h pin 15 is for button 3
                 {    
                   static scene_store_params_t store_params = {.scene_number = 1 }; // scene 1
                   recall_params.scene_number = store_params.scene_number;
     
                       if ( HAL_BUTTON_PRESS_DEBOUNCE_INTERVAL < TIMER_DIFF(m_last_button_press, timer_now()) && HAL_BUTTON_PRESS_LONG_PRESS_INTERVAL < TIMER_DIFF(m_last_button_press, timer_now()) )
                          {
                             __LOG(LOG_SRC_APP, LOG_LEVEL_INFO," Long press for scene 1 \n");
                       
                             //added for scene
                       //     __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);
    
                             m_last_button_press = timer_now();
                            button_handler_long_press(i);
                             //m_button_handler_long_cb(i);
                          }
    
                       else 
                           {
                           //   static scene_store_params_t store_params = {.scene_number = 1 };
                          //   __LOG(LOG_SRC_APP, LOG_LEVEL_INFO," Short press for scene 1 \n");
                             //added for scene
                       //     __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++;
    
                           m_last_button_press = timer_now();
                           button_handler_short_press(i);
                           //m_button_handler_short_cb(i);
    
    
                           }
                }
    
            else if ( pin == 19) // checking pin 19 for button 8, have given random pin as do not want button to utilized
             {
                static scene_store_params_t store_params = {.scene_number = 2 }; // scene 2
                recall_params.scene_number = store_params.scene_number;
    
                    if ( HAL_BUTTON_PRESS_DEBOUNCE_INTERVAL < TIMER_DIFF(m_last_button_press, timer_now()) &&  HAL_BUTTON_PRESS_LONG_PRESS_INTERVAL < TIMER_DIFF(m_last_button_press, timer_now()) )
                        {
                           __LOG(LOG_SRC_APP, LOG_LEVEL_INFO," Long press for scene 2 \n");
                        
                           //added for scene
                     //      __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);
    
                            m_last_button_press = timer_now();
                            m_button_handler_long_cb(i);
                        }
    
                    else 
                      {
                        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO," Short press for scene 2 \n");
                           //added for scene
                        //__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++;
    
    
                        m_last_button_press = timer_now();
                        m_button_handler_short_cb(i);
                      }
           }
                   
        }
            
         
    
           else  // checking other button except 7 and 8 
             {          
                /* 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)
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO," Other buttons apart from scene button \n");
                    m_last_button_press = timer_now();
                    m_button_handler_cb(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)
                {
                    m_last_button_press = timer_now();
                    m_button_handler_cb(i);
                }  */
    
          }
       }
    

    2) Shall i reset the "timer diff" after 512 second so that it will not impact the time difference?  or handling "timer diff" is required when we are exceeding the 512 second of operation?

    Thanks & Regards,

    Ekta

  • Hi Ekta, 

    1. I assume you have assiend m_button_handler_short_cb and m_button_handler_long_cb to the actual function in main.c  similar to this call in the original code: 

      m_button_handler_cb = cb;

    I am not sure why you need to call scene_client_store() inside the button_handler_long_press() function. You can call that in main.c inside the funtion that you mount to m_button_handler_long_cb . 

    2. You don't really need to solve this, in worst case it will end up as long press for a short press. What happens here is that when the button is first pressed the current counter is at for exampls 0xFFFFF8 then it's continue to count and the button is pressed and hold, and when the counter reaches 0xFFFFFF it will continue as 0x000000 

    And when the user release the button, the counter can be for example 0x000005. The TIME_DIFF between 0xFFFFF8 and 0x000005 will be 0xFFFFF3 which is a very large number. With the current implementation it will be accepted as a long press. But if you put an extra upper limit for the long press, for example if the press is longer than 20seconds you will reject the press. This will fix this corner case. 

Related