C++ wrappers, examples needed, please

I’ve got C++ code classes from which I want to run a C++ FreeRTOS task. I’m trying the C++ wrappers by Richard Damon, however:
I don’t normally use templates, so that’s a bit confusing, and I’ve not seen any examples.
Normally, I use the standard task create, and while things work with the task declaration outside the class, that has its own problems.

Are there any examples?

I’m looking for a simple class example with a task creation.

Currently semaphores and queues work well within a task, but the task has no access to the class variables.

Thanks

I’ve managed to get some of it, but the problem I’m currently having is that I haven’t figured out the syntax for passing the queue name to a queue, and while I have the task name done, how to pass the queue name is still a question.

I could add another parameter to the template, but it should work somehow…

There are several C++ wrappers for FreeRTOS - we are planning a page on the subject too - but at the moment Google will highlight several examples and articles.

I will point out that I have an open-source set of wrappers that I use a lot with FreeRTOS at GitHub - richard-damon/FreeRTOScpp: FreeRTOS C++ Wrappers

My Queue class is a template that takes as TEMPLATE parameters a “Type” parameter for the type of object stored in the Queue (which needs to be a ‘POD’), and a length parameter for the number of elements it will hold (to allow static creation of the Queue). The constructor then takes a const char* pointer (with a default of 0) as a name that gets registered.

It also allows a ‘0’ length as the template parameter (which is the default) which adds (before the name) a parameter for how long the queue will be for run time definition of size (or size independent typing), and such Queue are always created dynamically.

Thus you can define queues in the following ways:

Queue<MyType, 10> queue1;         // queue holding 10 MyTypes, no name registered
Queue<MyType, 10> queue2("Name");  // queue holding 10 MyTypes, registered with a name
Queue<MyType> queue3(10);       // Queue holding 10 MyTypes, dynamically created, no name
Queue<MyType> queue4(10,"Name");   // Queue holding 10 MyTypes dynamically created with registered name

Ok, there’s progress of sorts:

//		Queue<char[21],1> 				queue;
//		Queue<char[21],1> 				queue("Name");
		Queue<char[21]> 				queue(1,"Name");

This is going in a task created with TaskCPP and is placed in the taskname.hpp file.
It’s going there because I want it to be a normal member of the task, accessible from the task’s task implementation (read queue and put on screen), with other routines feeding the task. It’s updating a screen widget on a graphics display.

When uncommented, the first entry compiles.
The second entry generates a syntax error as does the third.
It looks as if you don’t intend for the queue definitions above to go into the HPP file, but only in the CPP file. This seems to limit access. The other definitions and instantiations work in the cpp file.

The other problem I have has to do with tasks, and exactly how to specify them. It looks as if the definition of the task wants a task defined as an instance of the template, then be derived from the user program.

Still trying to figure this out, but the queue definitions help a lot.

Thanks.

If you make the Queue to be members of a class, then in the class definition you just say something like:

class MyTask : public ClassTask {


Queue<char[21], 1>. queue1;
Queue<char[21]>. queue2;

}

Then in the constructor for the MyTask class, queue1 doesn’t need member initilization, unless you want to give it a name. queue2 NEEDS a member initilization, so something like:

MyTask::MyTask(…) :
TaskClass( …),
queue1(“Name”),
queue2(1, “Name”)
{
}

For Tasks, most of my Tasks are parts of classes that derive from TaskClassS<stack_size>> or TaskClass, with a void task(); member function that has the task code.

You can also create a task by creating an object of Class TaskS<stack_size> or of class Task, and provide it a function and input parameter. This second method basically just wraps the task creation and deletion into an object (and lets other tasks refer to that object to use the task control member functions provided in TaskBase.

OK, I’ve managed to get TaskClassS working, and included the queue (at least, one definition). Still having a problem with TaskS in how to specify the task itself in the constructor code.

My notes follow:

TASK:
Uses TaskCPP.
Given a class (String_widget).  Declare the class as follows:
class STRING_WIDGET: public TaskClassS<1000>, public String

Where the original definition was:

class STRING_WIDGET: public String

<1000> is the stack size for the class.  If <0> is given, task will not be created, but the class will be
Note that existing constructor and destructor code are not specified in the task code, but the inherited code from TaskClassS is used instead.
In the class constructor (note: needs separate instance per class and does not pass parameters)  Note that the name of the class for the registry is “String Widget” and the priority is TaskPrio_Mid.

This line must be modified if QueueCPP is used.
STRING_WIDGET(): TaskClassS("String widget",TaskPrio_Mid){};

which names the class “String Widget” and puts the class priority at 48, where the default class priority is 44.  This task priority may be adjusted. 



In the class that owns this instance (ex: screen.cpp), add:
 
string_widget = new STRING_WIDGET;			// new instance of class

with the definition in screen.hpp of

STRING_WIDGET*						string_widget;       // task is a pointer

STRING_WIDGET* is initialized by the constructor code in the template.  No other initialization needs to be done.  In the String Widget task (defined as:)

		void							task();

declare the task as:
 
void STRING_WIDGET::task()
{

{
 
In the task (as needed by the functionality)

use:
	while (1)
	{
		queue->pop(caption);
		set_CAPTION(caption);
		draw(0,{0,0},LOCATION_USE_ABSOLUTE);															// draw as designed
	}

I’d like to help with the documentation page, but I’ll have to understand a bit more.
Thanks

As a further note, the C++ wrapper seems to break certain aspects of virtual objects. String is a descendant of a virtual object class as every other graphics style object. Calling the “draw” routine with a pointer to the virtual object should (and normally does) call the draw routine of the appropriate object. In this case, with this code, it ends up in the task itself.

Making every STRING_WIDGET its own tasks doesn’t sound like the behavior I would normally expect, that is making a LOT of tasks for a typical GUI, and EVERY object that is derived from TaskBase (which includes TaskClassS) creates a new Task. Normally GUI objects are independent tasks, but just a method that is called that runs in the task of the calling object that does its operation. You are adding a LOT of task context switching, and the corresponding synchronization issues by using a lot of

If TaskPrio_Mid is 48, you have a LOT of Task Priorities, not sure why you think you need that many. I document how the priorities collapse on each other for configMAX_PRIORITIES < 6, because that is a common case. I see little reason in FreeRTOS for a number of priorities much more than that. Note, that a priority level without a task assigned to it is just wasting space and CPU cycles.

The Task base class should NOT affect other methods, but since the task method calls the draw method, it is quite possible that your debugger is getting confused, as a break point in draw gets hit by either call. (I hope that your basic graphic class isn’t also creating tasks, and then you have multiple task base sub-objects inside your object and those WILL interfere)

Now, if your draw member is pushing the caption for the task, you have just created a loop when it then calls draw.

The making each string widget (there will be 2, and the other widgets sum to 7) is needed mostly because some of them aren’t the same (the method of updating is different, could be a descendant of a class, was one, and then the C++ wrappers came along). I want each task to show up as a separate and recognized entity on the task list, which I had. The way that the C++ wrappers are structured enforces this. Otherwise, it could be an instance of a derived class of widget (difference is where they update and if another task is feeding the update). Not a big deal, but yes, this is a moderately complex system with a lot of I/O feeding a main receive queue, which then dispatches packets through several interfaces.

Normal graphics objects (string, for instance) simply know how to draw themselves, what their parent is, and where on the screen to go. They normally do not have tasks. They change only if the screen is drawn again (ie. changing screens). Only widgets live update. Examples of widgets are time, heap, network address, battery, NRF, WIFI, and caption.
Most of these widgets update every 100 ms or more, or only if there is a change (queue driven).

Almost everything in the system is packet driven, which vastly simplifies the remoting of displays and peripherals, so there are a number of tasks involving the queues.

Now for TaskPrio = 48, well. I didn’t do that. In the STM32 version of CMISS 2.0


#if (configMAX_PRIORITIES != 56)
  /*
    CMSIS-RTOS2 defines 56 different priorities (see osPriority_t) and portable CMSIS-RTOS2
    implementation should implement the same number of priorities.
    Set #define configMAX_PRIORITIES 56 to fix this error.
  */
  #error "Definition configMAX_PRIORITIES must equal 56 to implement Thread Management API."
#endif
#if (configUSE_PORT_OPTIMISED_TASK_SELECTION != 0)
  /*
    CMSIS-RTOS2 requires handling of 56 different priorities (see osPriority_t) while FreeRTOS port
    optimised selection for Cortex core only handles 32 different priorities.
    Set #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 to fix this error.
  */
  #error "Definition configUSE_PORT_OPTIMISED_TASK_SELECTION must be zero to implement Thread Management API."
#endif


So this wasn’t my idea. I was perfectly happy with task priorities from 0 to 5

The draw method sends off a packet to a queue, and that’s about it. The only tasks in graphics are are based on widgets, which need to be self updating. (or are intended to be so).
display packets are enqueued, dequeued, sent to the TFT driver which does magic and updates a display image, which then calls a task to copy the affected area of the virtual display image to the actual display hardware (where it isn’t a direct write).

The system advantage to this is that the board supports multiple displays in local hardware, and should support any remote display over any supported communications means (NRF, WIFI, SERIAL, I2C). Packet communications for these interfaces is done, or mostly done.

However, the graphics routines themselves, string, for instance is a descendant of a virtual object (graphics object). The various draw routines (per class of object) generally harken back to an instantiated routine for that kind of object. This is used to draw children of an object without knowing the class of the object.
Main difference is if the drawn is allowed to have children. Whole graphics draw walks down a tree of siblings and children, so drawing an object draws all the children, be they siblings or child objects of siblings (and so on). Some have children, some don’t.

The draw member for any object (however far it has to go down), produces a display packet and then sends that off to the main queue, which then routes it to the display driver. Don’t see how this creates a loop, though, since no other draw routine is called, just a routine in a parent class, which calls no other draw routines.

Seems complicated once I explain it.

The CMSIS requirement of 56 seems strange, but might be based on limitations of other RTOSes, I know some require each task to have a distinct priority.

The comment on the loop is that if a call to the objects draw gets you into the task function, then it seems that STRING_WIDGET draw must call the task (or push into its queue) which means that the draw() the task calls will go to THAT same function and get into a loop. I can’t see any other reason a call to “draw()” would end you up in the “task()” function.

I still wonder if this level really needs to be a task, and the making of it a task here removes the ability to make a task at a different level that implements the widget, which might actually have more need of that functionality.

Whatever routine you call that pushes the new caption on the queue could just as easily do the set_CAPTION and draw call (in the execution context of the caller) quicker and easier. It sounds like the draw function is fairly fast and queues up the packets to be sent.

Yeah, that 56 wasn’t my idea. Your programming takes care of that, but my fixed priorities (which worked) does not.

When the call to a virtual routine got to the task instead of the parent’s draw routine, I copied the code for the draw routine into the string_widget class rather than allowing it to call a predecessor class, and that worked. No idea why it didn’t, but that seems to be the fix.

The sequence is that the draw routine (for string widget) creates a packet, enqueues that. The packet dispatch routine dequeues that packet, determines the destination (local or somewhere out on the mesh network) and sends it out. For local packets, the dequeued packet then goes to the display driver routine.

The advantages to this are several:

  1. the original routine can bypass the queue, but that limits it to local only. Not bad, but it kills the idea of remote displays.
  2. putting it on the queue makes no comment about where the packet came from, so if a packet on the queue is properly processed, then the whole queue mechanism works for that packet type.
  3. that means that the packet can come from anything that can feed the queue, and I know it will work if the packet is properly formed.

The idea behind this whole thing is that you declare a remote resource (display at a mesh address), and then by simply specifying that display, you can write to it at the system/application level and let the underlying software take care of the dirty necessities.

The mechanism has been proven by other routines, such as LED flashing. One thing that is implemented is an NRF mesh network, and that case is working.

Do you have a bit of an example for taskS?
I’m going to fork the whole project and then rewrite that copy to use C++ tasks, but it can’t be done halfway. Because the processor has available to it QSPI memory (which is slower), some tasks need to be in the extended RTOS heap space, and some need to be in the processor memory space. I’ll need to do static tasks.

thanks again.
your suggestions are welcome.

I think my idea is that your GUI is always local, (even if the display is remote) and thus whatever is pushing onto the queue could also just call the routine. If the packet’s original source was remote, it still had to go through a local intermediary to push onto the queue, and that is where the call would be.

A simple task created with TaskS would be something like:

/* Task Function for a FreeRTOS task */
void myTaskFun(void* parm) {
...
}

TaskS<1000> myTask("TaskName", myTaskFun, TaskPrio_Mid, parm);

or

TaskBase* task = new TaskS<1000>("TaskName", myTaskFun, TaskPrio_Mid, parm);

TaskS doesn’t actually do much except provide a “Task Object” that other tasks can reference or that can be made a global to automatically create the task. The constructor calls xTaskCreateStatic on the buffer created in the object (or xTaskCreate if the template parameter is 0, and then you need to add the stack size as a parameter to the constructor call)

I normally use TaskClassS based tasks as I put most of my tasks into a class. The TaskS version just makes a class out of the handle to the task, and can automate the call to the create function, the task doesn’t end up part of a class.

ah, thanks.
Yes, your idea is correct. The graphics tree and the software to deal with it are always on the “local” computer. The packet contains enough information to draw the primitive on the display, in this case (hopefully) regardless of where it is.

The widget tasks simply put drawing packets to draw the primitive on the queue. The routing information controls where it goes.

The remote display driver can report a touch panel task (haven’t debugged this part yet), and that goes back to the main processor. that would then tell the remote processor “xxx object was touched”. Still have to think this one through. The interplay between to networked processors has to be thought out, and what you mentioned has provoked a redesign, I think.

In this system, as I see it working, the TaskClassS method is the one I’d use, since I have a fully developed C++ system on top of FreeRTOS.

But it needs to be both statically allocated and dynamically allocated, some depending on a choice for certain tasks (for speed).

Thanks. More playing with this tomorrow.

One thing to note is that even though the TaskClassS class calls xTaskCreateStatic, and that means that FreRTOS doesn’t do any memory allocations, you can still create that object with new and make the whole thing dynamic. There is nothing in xTaskCreateStatic (or any of the other xxxCreateStatic functions) that prevent the memory they are using from being obtained dynamically by the caller.

Thanks.
Down at the hardware level, the STM32L562VETQ processor was, about the beginning of the year, the only processor left to be ordered (it lacked a few pins and had an onboard switching regulator in the TFQP100 package). But, I could get them from Mouser.

Turns out to be pin limited mostly, but workable enough. 512K flash, 256K SRAM. For the graphics trees and queues, I was running close to the processor’s SRAM limit, so the L5 series has an OctoSPI interface, which can be run in QSPI mode, and can have a 64MBit QSPI memory added to the processor. Instant no RAM memory problems, but you can have just one (No flash, needs a dual OctoSPI interface). the QSPI memory is slower, and while the long period tasks work well enough (put the FreeRTOS heap in extended memory), the faster tasks (like display update) benefit from being in faster processor memory. Hence the need for statically located tasks.

Just as a hardware note, it’s a 4 layer board with 22 ohm damping resistors in the QSPI control signals. Seems pretty reliable so far.

thanks again

Looks like I need the syntax for including a semaphore in TaskClassS. From what I can see, this might be the last of what I need.

Busy rewriting software to make all the tasks C++

Thanks

The key to putting something like a semaphore into a class is to realize it goes in two places.

First, in the class definition, among all the other member variables, would be a simple line like:

    Semaphore  sema;

Then, because I haven’t made the name optional (probably could), in the initialization section of the constructor for the class you need to add a clause like

MyClass::MyClass( ... )  :
 TaskClassS( ...),
...
  sema("SemaName"),
...
{
   ....
}

if you change the constructor definition for the Semaphore to

   Semaphore(const char*name = 0);

Then you don’t need the initialization clause if you don’t need the name. I have kept it required so I don’t forget to name my semaphores.

Got that and it compiles.
You don’t do pointers to tasks all that much?

Making a pointer to the task, then trying newclass = new MyClass;
gives me an error for an undefined reference to MyClass::MyClass();

making the reference to be : MyClass newclass; // this works
MyClass* newclass; // will result in errors.

I actually had your solution implemented, but ran into the specific error above.

Figured I’d ask, since if you don’t do pointers to classes all that much…
Oh, and the pointer to the class works, and works if there’s a queue included. Semaphore? Not the right syntax I think.

Thanks

MyClass* new class = new MyClass; 

Should work if your class constructor takes no arguments, which sounds like is true if you can just say

MyClass newclass;

You HAVE defined the constructor MyClass::MyClass() for both of these to call. Since the TaskClassS base class needs parameters, the default constructor just won’t work.

Since Queue can be created with just template arguments, it won’t cause a problem adding to a class that otherwise can just use the default constructor. Since Semaphore currently NEEDS a name parameter, the compiler can’t make a default constructor, so you need to provide one.

As a rule, I always write a constructor for every Class I create, and not rely on the default, to provide a place to make sure everything is initialized.