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

APP_TIMER_DEF for several timers with same timer id. like C++ class member

hello

yes I have problems with my app_timers in SDK14.2 (migration from 12),

I well noticed that the prototypes of the functions create and start changed from sdk12.

// create timer

static app_timer_t timer_data = { {0} };
m_timer_id = &timer_data;
err_code = app_timer_create(&m_timer_id, APP_TIMER_MODE_REPEATED, cbk_measure);
APP_ERROR_CHECK(err_code);
-> this works well
ret_code_t err_code;
err_code = app_timer_start(m_timer_id, APP_TIMER_TICKS(m_probing_interval_ms), (void *) this);
NRF_LOG_DEBUG("FIXME: app_timer_start returns %d", err_code);
// APP_ERROR_CHECK(err_code);
-> but the start returns error code 8 (invalid param if i remember correctly) and I dont understand why. I tried APP_TIMER_DEF, but my timer_ids are C++ class members. I cannot simply use the APP_TIMER_DEF macro because I dont know if it ok if already declared. but it was already the case ion SDK12 and worked AFAIK

thx,

yacine

Parents
  • The APP_TIMER_DEF macro instantiates an app_timer_id_t with the name you provide and another variable of type app_timer_t with the name appended with _data. app_timer_id_t is just a pointer to the app_timer_t (app_timer_t *).

    For example:

    APP_TIMER_DEF(my_timer);

    expands to

    static app_timer_t my_timer_data = { {0} };
    static const app_timer_id_t my_timer = &my_timer_data;

    So far so good, unless you want an app_timer to be a member of a struct or class, which is the problem I also ran into quickly. In that case, just do the same thing as the macro would, manually, and in your initialization code or constructor, set the app_timer_id_t member to the address of the timer.

    In C++:

    #include <cstdint>
    
    using std::uint32_t;
    
    class my_timer_class {
        public:
        my_timer_class()
        : timer(&timer_data)
        , timer_data()
        {
            app_timer_create(&timer, APP_TIMER_MODE_REPEATED, timer_handler_s);
        }
        
        virtual ~my_timer_class()
        {
        }
        
        void start_timer(const uint32_t ms)
        {
            app_timer_start(timer, APP_TIMER_TICKS(ms), this);
        }
        
        private:
        app_timer_id_t timer;
        app_timer_t timer_data;
        
        static void timer_handler_s(void *p_context)
        {
            ((my_timer_class*)p_context)->timer_handler();
        }
        
        void timer_handler()
        {
          //timer expired, do something!
        }
    };
    
    my_timer_class timer_object;
    
    int main() {
      //start object's timer qith 1000 ms period
      timer_object.start_timer(1000);
    }

    In C, you either have to do the initialization at the time of instantiation or not make the app_timer_id_t const:

    #include <stdio.h>
    #include <stdint.h>
    
    typedef struct struct_with_timer_s {
      const app_timer_id_t timer;
      app_timer_t timer_data;
    } struct_with_timer_t;
    
    //initialize timer_id (const) when declaring struct
    struct_with_timer_t struct_with_timer = {.timer = &struct_with_timer.timer_data};
    
    void struct_with_timer_handler(struct_with_timer_t *const this)
    {
      //timer expired, do something!
      printf("tick\n");
    }
    
    void struct_with_timer_static_handler(void * p_context)
    {
      struct_with_timer_handler((struct_with_timer_t *)p_context);
    }
    
    void struct_with_timer_init(struct_with_timer_t *const this)
    {
      uint32_t error_code = app_timer_create(&this->timer, APP_TIMER_MODE_REPEATED, struct_with_timer_static_handler);
      APP_ERROR_CHECK(error_code);
    }
    
    void struct_with_timer_start(struct_with_timer_t *const this, const uint32_t ms)
    {
      app_timer_start(this->timer, APP_TIMER_TICKS(ms), this);
    }
    
    int main(void) {
      //initialize struct
      struct_with_timer_init(&struct_with_timer);
      //start its timer with 1000 ms period
      struct_with_timer_start(&struct_with_timer, 1000);
      return 0;
    }
    

Reply
  • The APP_TIMER_DEF macro instantiates an app_timer_id_t with the name you provide and another variable of type app_timer_t with the name appended with _data. app_timer_id_t is just a pointer to the app_timer_t (app_timer_t *).

    For example:

    APP_TIMER_DEF(my_timer);

    expands to

    static app_timer_t my_timer_data = { {0} };
    static const app_timer_id_t my_timer = &my_timer_data;

    So far so good, unless you want an app_timer to be a member of a struct or class, which is the problem I also ran into quickly. In that case, just do the same thing as the macro would, manually, and in your initialization code or constructor, set the app_timer_id_t member to the address of the timer.

    In C++:

    #include <cstdint>
    
    using std::uint32_t;
    
    class my_timer_class {
        public:
        my_timer_class()
        : timer(&timer_data)
        , timer_data()
        {
            app_timer_create(&timer, APP_TIMER_MODE_REPEATED, timer_handler_s);
        }
        
        virtual ~my_timer_class()
        {
        }
        
        void start_timer(const uint32_t ms)
        {
            app_timer_start(timer, APP_TIMER_TICKS(ms), this);
        }
        
        private:
        app_timer_id_t timer;
        app_timer_t timer_data;
        
        static void timer_handler_s(void *p_context)
        {
            ((my_timer_class*)p_context)->timer_handler();
        }
        
        void timer_handler()
        {
          //timer expired, do something!
        }
    };
    
    my_timer_class timer_object;
    
    int main() {
      //start object's timer qith 1000 ms period
      timer_object.start_timer(1000);
    }

    In C, you either have to do the initialization at the time of instantiation or not make the app_timer_id_t const:

    #include <stdio.h>
    #include <stdint.h>
    
    typedef struct struct_with_timer_s {
      const app_timer_id_t timer;
      app_timer_t timer_data;
    } struct_with_timer_t;
    
    //initialize timer_id (const) when declaring struct
    struct_with_timer_t struct_with_timer = {.timer = &struct_with_timer.timer_data};
    
    void struct_with_timer_handler(struct_with_timer_t *const this)
    {
      //timer expired, do something!
      printf("tick\n");
    }
    
    void struct_with_timer_static_handler(void * p_context)
    {
      struct_with_timer_handler((struct_with_timer_t *)p_context);
    }
    
    void struct_with_timer_init(struct_with_timer_t *const this)
    {
      uint32_t error_code = app_timer_create(&this->timer, APP_TIMER_MODE_REPEATED, struct_with_timer_static_handler);
      APP_ERROR_CHECK(error_code);
    }
    
    void struct_with_timer_start(struct_with_timer_t *const this, const uint32_t ms)
    {
      app_timer_start(this->timer, APP_TIMER_TICKS(ms), this);
    }
    
    int main(void) {
      //initialize struct
      struct_with_timer_init(&struct_with_timer);
      //start its timer with 1000 ms period
      struct_with_timer_start(&struct_with_timer, 1000);
      return 0;
    }
    

Children
No Data
Related