Do you struggle with multitasking or events in your project?

Hi All,

Looking for ideas to help test the limits and show off the utility of my multitasking (for Uno/MKR) and eventing libraries Taskfun and Eventfun. By multitasking I mean you are working on a project where you wish you could do like this

void loop2(int) {
  while(1) {
     // do stuff in parallel with other loops
     // for example play song
   }
}

void loop3(int) {
  while(1) {
    // do stuff in parallel with other loops
    // for example draw the game screen
  }
}

void setup() {
  setupTasks();
  runTask(loop2, 0);
  runTask(loop3, 0);
}

void loop() {
  // do stuff in parallel with other loops
  // for example read input from joystick and buttons
}

Events are most useful in combination with classes but can be used without them. And by eventing I mean that you wish you could do something like this

// attach 2 listeners to the same event
joystick.OnMove += onJoystickMove1;
joystick.OnMove += onJoystickMove2;

// trigger the event
OnMove(this /* event sender */, JoystickMoveArgs(joystickX, joystickY) /* event parameter */);

// declare event listener
void onJoystickMove1(Joystick* sender, JoystickMoveArgs args) { 
  // respond to event
}

void onJoystickMove2(Joystick* sender, JoystickMoveArgs args) { 
  // also respond to the same event
}

The libraries provide the bare minium functionality to fit many different projects. I implemented some examples for the libraries that I think show the utility of the library but are themselves not useful. So I want to test it on real scenarios especially if you are looking for simple solutions for your project because simplicity of use was one of the main design goals. Both libraries should be available in the Arduino library repository. Please let me know if you have a project where these can help. Thanks!

glutio/Eventfun: Building blocks for event driven Arduino sketches (github.com)
glutio/Taskfun: Minimalist preemptive multitasking for Arduino (github.com)

I´m using a bag of structured function pointer simply.

2 Likes

:+1: A solid solution. Eventfun also supports nonstatic class methods with this syntax

class Program {
public:
  Program() {
    joystick.OnMove += Joystick::MoveEvent(this, &Program::onJoystickMove);
  }
protected:
  void onJoystickMove(Joystick* sender, JoystickEventArgs args) { 
    // ... 
  }
}
void loop0() { Serial.println(__func__); }
void loop1() { Serial.println(__func__); }
void loop2() { Serial.println(__func__); }
void (*loops[]) () {loop0, loop1, loop2};
void setup()
{
  Serial.begin(9600);
  delay(500);
}
void loop() {
  for (auto loop_:loops) loop_(), delay(1000); 
}

That's not multitasking, that's just calling them one by one. Multitasking will interrupt execution of one loop and execute another for a short period and interrupt that too and get back to the first one and then back to the second one giving an illusion they run in parallel and in your example it's just sequential.

up to you

Have a nice day and enjoy coding in C++.

Computer multitasking - Simple English Wikipedia, the free encyclopedia Have a nice day!

some Woodoo that creates events?

I tried to target beginners, so I provied a templated class SyncVar<> that overloads all operators and wraps the operations in noInterrupts()/interrupts(), this is not ideal but solves many (not all) basic problems and can be used like this

SyncVar<bool> _on(false);

void taskOn() { 
  while (1) if (_on) { 
     // do On stuff
    _on = false;
  }
}

void taskOff() { 
  while (1) if (!_on) { 
     // do !On stuff
    _on = true;
  }
}

Agree, that's why I did not provide Mutex or Semaphore as part of the library (I provided the implementation in the example) - they should implement it themselves!

Happy to provide more details if you have a specific question!

How do I specify an event?

For example if you want a button to fire an OnClick event you specify it like so:

class Button {
public:
  // specify event 
  EventSource<Button, ButtonClickArgs> OnClick;
};

void onClickHandler(Button* sender, ButtonClickArgs args) { 
  // do stuff 
}

// instantiate button class
Button button;

// attach event listener
void setup() {
  button.OnClick += onClickHandler;
}

And your Button class handles the button interrupt? How that?
Including debouncing? Double clicks? Long click?

Or if I want an event if my motor looses speed, how do I specify that?

In basic sketches I envision that the main loop will call button.Update() and the Update() will decide wether to trigger the event

Button::Update() {
  auto new_reading = digitalRead(buttonPin);
  if (new_reading != _old_reading) {
     _old_reading = new_reading;
     if (new_reading == LOW) { // button clicked
        ButtonClickArgs args; // populate whatever arguments you have
        OnClick(this, args); // trigger the event with these arguments
     }
  }
}

void loop() {
  button.Update();
}

You specify the event the same way, it's unrelated to how you detect that the motor lost speed. As long as you can detect it, you can fire the event you specified like OnMotorSlowdown

So I also could write in the main loop:
if (button.pressed) OnClick();
if (myMotor.slowedDown) OnMotorSlowDown();
and do what I want there immediately.

Yes, it's possibe, except only the button class can trigger its own event so you would need to have some method on the button class to do it then

The button class can check for an event in the button.pressed() call or getter.

1 Like

The trajectory of this thread reminds me of that of a similar multitasking development named as a_coos by its author which started at this post part way in another thread: Arduino Operating System - #28 by akouz

They say theirs is a cooperative multitasking system, but Taskfun is true preemptive multitasking, this is my pride :slight_smile: , but it can also be in cooperative mode if you want

That's nice on a desktop computer but not so nice on a µC. I only can see complications in handling even most basic events.

First the user has to understand and write a Program class.
Next he has to understand and configure a Button class,
and add its update to the main loop.
Then he has to write an OnClick handler.
When called, the OnClick handler has to check which button was pressed and which task handles that event, before it can notify that task of the button click.

Isn't that a bit too excessive?