C++ Class for FreeRTOS

blacknz wrote on Tuesday, March 18, 2008:

Hi Everybody,

I’m writing to see if anybody has written a C++ class that encapsulates the FreeRTOS functionality.

I’m asking as I am considering doing this and don’t want to reinvent-the-wheel so to speak.

The main stumbling point as far as I see it is the tasks require a "c" function (which is a problem if your task is part of an object).
But I think there is a way around this by using a static function which calls a virtual task function which is overridden( this->myTask() ).

Has anyone done this?
Are you willing to share code or offer any advice for someone who is about to do this?

Best regards
blacknz

rtel wrote on Wednesday, March 19, 2008:

I am aware of lots of people using FreeRTOS.org in C++ applications, but only by extern “C”'ing the code.  I am not aware of anybody encapsulating the functionality in a class.  It would be an interesting exercise.

Regards.

richard_damon wrote on Thursday, March 27, 2008:

I did it like this:

#ifndef TaskCPP_H
#define TaskCPP_H

#include "FreeRTOS.h"
#include "task.h"

class TaskBase {
public:
  xTaskHandle handle;
 
  ~TaskBase() {
#if INCLUDE_vTaskDelete
    vTaskDelete(handle);
#endif 
    return;
  }
};

class Task : public TaskBase {
public:
  Task(char const*name, void (*taskfun)(void *), unsigned portBASE_TYPE priority,
       unsigned portSHORT stackDepth=configMINIMAL_STACK_SIZE) {
    xTaskCreate(taskfun, (signed char*)name, stackDepth, this, priority, &handle); 
  }
 
};

#endif

This version took a free funciton with the right signature and used the class to just automatically create the task block for the function. (On this processer the “C” wasn’t needed as the calling convection for C and C++ were the same).

It was split into 2 classes so I could define other variants with different type of task funs. Too make one that used class members functions as tasks it would be something like (warning untested code):

class ClassTaskBase : public TaskBase {
public:
  ClassTask(char const*name, unsigned portBASE_TYPE priority, unsigned portSHORT stackDepth=configMINIMAL_STACK_SIZE) {
    xTaskCreate(&runtaskstub, (signed char*)name, stackDepth, this, priority, &handle); 
  }

  virtual void runtask() = 0;
  static void runtaskstub(void* parm) { (static_cast<ClassTaskBase*>(parm))->runtask(); }
};

You can then derive a class from ClassTaskBase and it will run the runtask member as the task.

anonymous wrote on Thursday, March 27, 2008:

Sorry, just got back from a vacation, so I am late responding.

Yes I have reasonably object oriented wrappers for threads and what I call synchronization primitives. I also have an object oriented framework for device drivers. I am quite busy on a contract where this is in commercial use and have not had the time to get it out there in the public. However, if I get email to “info @ EmbeddedClarity.com” (drop the spaces) I will try to reply with zipped text of the header files. Then, if there is interest, I can maybe get to work on making it more available for others to try out. I just don’t want to get too tied up with supporting it quite yet.

For threads, there is a Thread base class. Instances of derived classes represent threads in the system. An entry() virtual member function is supplied to provide the thread code. A subclass RichThread supports thread safety for newlib C functions that need per-thread re-entrancy functions. Both classes need minor changes to the FreeRTOS (ARM only) port. For Thread a patch is needed so that a thread can find its own object instance. For RichThread a patch is needed to switch the newlib _impure_ptr during context switches, so that each thread can have its own reentrancy structure.

In this implementation, threads are truely objects with member functions that affect thread scheduling in the FreeRTOS kernel (suspend(), resume(), priority()). Such member functions allow one thread to affect another using a reference to the other thread object. But several scheduling operations don’t make sense to have one thread perform it on another. A Thread can only perform the operation upon itself (such as Delay()). For these, class (static) functions are used. But the class function is not passed the reference to the current thread object. The object can be discovered because of the above mentioned patch. For example, Delay(50) delays the calling Thread for 50 msec.

There is no co-routine support.

Synchronization primitives are layed on top of FreeRTOS queues. There is class Resource that provides for recursive locking of resources (mutex to a resource). There is a simple Signal class - essentially a binary semaphore. Full FreeRTOS queues are carried through as class SynchQueue. A cute class called Access is available that facilitates locking based on static nesting of the C++ code rather than freestyle calls to lock() and unlock() within the dynamic flow of control. This ensures proper pairing - a Resource locked() for the execution of a block is unlocked() when the block is exited - no matter how the block is exited (break, return, continue, etc).

The device driver architecture is really not ready for any kind of release, although I guess I could be pressured to show some of the base class header files. This is not really a FreeRTOS topic, but I will through it out here and further discussing could be picked up with me directly.

There is serial port support (for a few UARTs), TCP/IP over lwIP, and even a Flash file system layer. However there are both technical and license issues with this stuff, and I have no idea if/when I will be able to provide it. With some work I will be able to at least provide a UART framework, but maybe not ISR details for all the UARTs currently supported. I should be able to do something regarding lwIP because I have had the upper layers running over lwIP in the past, and they are running commercially over another commercial TCP/IP stack (the old USNet and now smxNS TCP/IP stack). The file system aspect is a no-go until I find a free file system software (a RAM file system, maybe).

My device driver and file system layers are a class hierachy that lays on top and must be adapted to other underlying drivers, but provide a somewhat uniform device/file interface to higher layers. I have a higher layer that implements the file descriptor oriented open(),close(),read(),write() stuff for newlib. Both the FILE * and file descriptor I/O functions operate nicely for both blocking and non-blocking I/O.

Glen