Home > database >  Can you use a macro or function in C/C to construct incrementing tasks?
Can you use a macro or function in C/C to construct incrementing tasks?

Time:11-24

When I create a new software project, I do it via a script which makes the folder, copies and moves some files and generate some source code.

One of the copied files is called roundRobinTasks.cpp. Obviously it is ment for round robin tasks like reading the from the serial buffer, handle can bus communication, monitoring emergency switch etc.

This file contains one function which looks as following:

void processRoundRobinTasks(void) 
{
    static unsigned char taskCounter = 0;

// HIGH PRIORITY ROUND ROBIN TASKS


// LOW PRIORITY ROUND ROBIN TASKS
    switch(    taskCounter )
    {
    default: 
        taskCounter = 0;
        
        /* fill in a task */
        break;

    case 1:
        /* fill in a task */
        break;

    case 2:
        /* fill in a task */
        break;
    }
}

This function is called every program cycle in int main() and I split tasks into a high priority or a low priority task. Every high prio tasks is run every cycle, only 1 low prio task is run every cycle.

The taskCounter is an ever incrementing static variable. The idea is that for every new task you can add a new case label with an incrementing number. If taskcounter becomes greater than the highest task, the default label will set it back to 0. This prevents the need to pre define the amount of tasks.

To make it look prittier, I was looking into a couple of macros and I quickly arrived at this situation. I already filled in some details of what one could fill in.

void foobar()
{
    // code
}

void processRoundRobinTasks(void) 
{
HIGH_PRIORITY_TASKS

    foobar() ; 

LOW_PRIORITY_TASKS

    TASK(1)
        REPEAT_MS( 500 )
        TGL( PORTB, 5 ) ;           // is run every 500ms
        END_REPEAT

    TASK(2)
        REPEAT_MS( 50 )
        handleSomething() ;         // is run every 50ms
        END_REPEAT

    TASK(3)
        doSomethingElse() ;
    
    TASK(4)
        /* fill in a task */

    
END_TASKS
}

It compiles fine with these macros and it works the exact same.

#define HIGH_PRIORITY_TASKS static unsigned char taskCounter = 0;
#define LOW_PRIORITY_TASKS  switch(    taskCounter ) \
                            { \
                            default : \
                                taskCounter = 0 ;

#define TASK(x)             break ; case x:
#define END_TASKS           break ; \
                            }

With or without the macros, there is one minor bug possibility. If a user adds or removes a task and forgets to update all the task numbers, there will be tasks which may never be called like in this example.

    default: 
        taskCounter = 0;

        /* fill in a task */
        break;

    case 1:
        /* fill in a task */
        break;

    case 3:             // because task 2 does not exist I will never run     
        /* fill in a task */
        break;

I am interested in a construct, in which I can simply type TASK or if( Task() ) without a number followed by an actual task to do like:

void processRoundRobinTasks(void) 
{
HIGH_PRIORITY_TASKS

    foobar() ; 

LOW_PRIORITY_TASKS

    TASK
        REPEAT_MS( 50 )
        handleSomething() ;         // is run every 50ms
        END_REPEAT

    TASK
        doSomethingElse() ;
    
    TASK
        /* fill in a task */

    
END_TASKS
}

I am not limited to calling a function. I essentially can do whatever I want in this code.

I believe that it cannot be done with a function. I for one could not think of anything.

Can something like this be done with a macro? Are there other constructs for this such as a list with function pointers?

CodePudding user response:

How about something like this:

#define HIGH_PRIORITY_TASKS static unsigned char taskCounter = 1;
#define LOW_PRIORITY_TASKS  switch( taskCounter ) \
                            { \
                            default : \
                                taskCounter = 1 ;

#define TASK(x)                 taskCounter = (x); \
                                break ; \
                            case (x):
#define END_TASKS               taskCounter = 1; \
                                break ; \
                            }

The idea is to update taskCounter to the next task just before breaking out of the switch. It shouldn't matter if there are gaps in the taskCounter values.

  • Related