Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 8 months ago.
How can I refactor my static logic into a generic class that implements callback functions
Hi there, I've written a program to call a function based on the duration of a button press. Now I'd like to wrap this into a class and make it more generic so I could use it in a similar way
myduration buttonDuration(); myduration.add(after1, 1); myduration.add(after3, 3); myduration.add(after8, 8);
I've posted a question on stackexchange as I though this would be a more C++ generic question but the advise I got make use of STL classes such as iostream or maps which can't or shouldn't be used on mbed.
Any hint would be of great help!
Thanks, Jens
My program looks like this:
#include "mbed.h" DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); Serial pc(USBTX, USBRX); Ticker ticker; InterruptIn pb(p17); void state1(void){ led2 = !led2; } void state2(void){ led3 = !led3; } void state3(void){ led4 = !led4; } // Global count variable int volatile counter = 0; int volatile STATE = 0; void countCallback(void) { counter = counter + 1; } void stateEval(void) { if(counter >=1 && counter <=3){ STATE = 1; state1(); } if (counter >= 4 && counter <=7){ STATE = 2; state2(); } if (counter >=8 && counter <=10){ö STATE = 3; state3(); } pc.printf("STATE %d \n", STATE); } // pb Interrupt routine - is interrupt activated by a falling edge of pb input void pb_hit_interrupt (void) { ticker.attach(countCallback, 1); counter = 0; } void pb_release_interrupt (void) { ticker.detach(); stateEval(); counter = 0; STATE = 0; // pc.printf("Counter: %d \n", counter); } int main() { // Use internal pullup for pushbutton pb.mode(PullUp); // Delay for initial pullup to take effect wait(.01); // Attach the address of the interrupt handler routine for pushbutton pb.rise(&pb_release_interrupt); pb.fall(&pb_hit_interrupt); // Blink led1 in main routine forever while responding to pb changes // via interrupts that activate pb_hit_interrupt routine while (1) { led1 = !led1; wait(.5); } }
This is the ButtonPressDuration Library so far. For some reason the "press()" and "release()" functions attached to ButtonPin.raise and fall are never executed.
#include "mbed.h" Serial pc(USBTX, USBRX); struct action { int counter_limit; void (*transition)(void); }; struct action_list { size_t size; const action *table; }; class ButtonHandler { public: ButtonHandler(std::size_t table_size, const action* begin, PinName pin, float seconds ): buttonPin(pin) { mTable.size = table_size; mTable.table = begin; // buttonPin(pin); intervalInSeconds = seconds; pc.printf("class initialized \n"); } void react(int counter) const { const action *a = mTable.table; for (std::size_t i=mTable.size; i; --i, ++a) { if (counter < a->counter_limit) { a->transition(); return; } } } void enable() { buttonPin.mode(PullDown); wait(0.01); buttonPin.rise(this, &ButtonHandler::release); buttonPin.fall(this, &ButtonHandler::press); buttonPin.enable_irq(); pc.printf("enable() function executed\n"); } void disable() { buttonPin.disable_irq(); ticker.detach(); } virtual ~ButtonHandler() { disable(); } protected: void press() { pc.printf("button 1 pressed\n"); counter = 0; ticker.attach(this, &ButtonHandler::secondsCount, intervalInSeconds); } void secondsCount() { ++counter; } void release() { ticker.detach(); react(counter); counter = 0; } private: volatile unsigned counter; InterruptIn buttonPin; float intervalInSeconds; action_list mTable; Ticker ticker; }; void state1() { //std::cout << __func__; pc.printf("state1"); } void state4() { //std::cout << __func__; pc.printf("state4"); } void state8() { //std::cout << __func__; pc.printf("state8"); } const action action_table[] = { { 4, state1 }, { 8, state4 }, { 11, state8 }, }; int main() { ButtonHandler green( sizeof(action_table)/sizeof(action_table[0]), action_table, p17, 1 ); green.enable(); while(1){ printf("alive\n"); wait(5); } }
1 Answer
8 years, 8 months ago.
A relative simple library which uses callbacks is for example: https://developer.mbed.org/users/Sissors/code/WakeUp/ (the attaching/adding is done in the .h file, the .cpp files call the actual functions, the LPC812 is a quite simple one to see what it does).
Then your only other job is to add the InterruptIn to that library.
Thanks Erik! After reading your example library I understand how to implement the callback part but I struggle with the routine to map callback functions to the actual timer values. Since "map" does not exist on med and I can't do something like:
using state_caller = std::map<int , std::function<void()>>;
Having a 2 dimensional array with different datatypes doesn't seem to work either. Any idea?
Cheers, Jens
posted by 18 Mar 2016Since it seems to be a standard C++ function (and not only for latest C++) I would expect that std::map can work.
You can make a 2D array based on pointers, or 2 1D arrays (easier), one with time values, other one with FunctionPointers. Downside is you need to know beforehand how many you can add to your list. Otherwise you can for example use a LinkedList (there is a good library for that floating around), but I would prefer to just make (semi) fixed number of callbacks you can attach.
posted by 18 Mar 2016With quite some help from stackreview I got the library almost ready. I still have problems with the InterruptIn setup in function enable() as press() and release()functions are never being triggered. (I've updated the initial post with the current code)
posted by 31 Mar 2016
Ok, problem is solved. I've made a library out of this available from here: https://developer.mbed.org/users/jensstruemper/code/PushDuration/
posted by Jens Strümper 28 May 2016