FreeRTOS Task in C++ erzeugen

(Firma: S+S) #3189332
Lesenswert?

Hallo zusammen,

hat hier jemand vielleicht Erfahrung mit der Erstellung von Tasks in 
C++?

Leider bekomme ich das selbst nicht auf die Reihe...

Hier mal mein Code:

ioCtrl.cpp
1
/* INCLUDE FILES **************************************************************/
2

3
/* IMPORT */
4
#include "common.h"
5
//#include "TaskWrapper.h"
6
/* FreeRTOS */
7

8
#if defined(__cplusplus)
9
extern "C" {     /* Make sure we have C-declarations in C++ programs */
10
#endif
11

12
#include "FreeRTOS.h"
13
#include "task.h"
14
#include "queue.h"
15
#include "timers.h"
16

17
#include "ioCtrl.h"
18

19
#if defined(__cplusplus)
20
}     /* Make sure we have C-declarations in C++ programs */
21
#endif
22

23
/* EXPORT */
24

25

26

27
void ioCtrl::task(void)
28
{
29
  vErrorMessage( "Task is starting!", 0, RADIX_NO_VALUE, 0 );
30
  portTickType xLastWakeTime;
31
    xLastWakeTime = xTaskGetTickCount();
32

33
    for(;;) {    
34
        //debug_printf("TestTask[%d]\n", this->xtest);
35
    vErrorMessage( "Task is running!", 0, RADIX_NO_VALUE, 0 );
36
      //Delay für 1000ms
37
      vTaskDelayUntil(&xLastWakeTime, ( 1000 / portTICK_RATE_MS ) );
38
    }
39
}
40

41
int ioCtrl::start(void)
42
{
43
  xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, ((void *) 0), (unsigned long)1, (unsigned long)0);
44
    
45
  //xTaskGenericCreate(doTask, (const signed char*)"Task", 240, NULL, (unsigned long)1,  (unsigned long)0, (void *) 0, (const xMemoryRegion*) 0);
46
  
47
  /*if( xTaskGenericCreate(&taskrun, (const signed char*)"Task", 240, ((void *) 0), (unsigned long)1, (unsigned long)0, (unsigned long *)0, (xMemoryRegion *)0) != pdPASS)
48
    vErrorMessage( "Insufficient heap memory available to create ControlTask!", 0, RADIX_NO_VALUE, 0 );
49
  else
50
    vErrorMessage( "Task created successful!", 0, RADIX_NO_VALUE, 0 );*/
51
}


ioCtrl.h
1
#ifndef _IOCTRL_H
2
#define _IOCTRL_H
3

4

5
/// Refresh intervall in ms for ioCtrl.
6
#define SYSCNF_IOCTRL_UPDATE_INTERVAL       25
7
#define _CONTROL_QUEUE_LENGTH        10
8
#define _CONTROL_TASK_STACK_SIZE      192
9
/* Application task priorities */
10
#define CONTROL_TASK_PRIORITY               4
11

12
#if defined(__cplusplus)
13
extern "C" {     /* Make sure we have C-declarations in C++ programs */
14
#endif
15

16
class ioCtrl
17
{
18

19
private:
20

21
public:
22
  /// constructor
23
    ioCtrl() {}
24
    /// destructor
25
    ~ioCtrl() {}
26
  
27
  
28
    void task(void);
29
    int start(void);
30
};
31

32
extern "C" void taskwrapper(void* parm) {
33
    (static_cast<ioCtrl*>(parm))->task();
34
}
35

36
#if defined(__cplusplus)
37
}     /* Make sure we have C-declarations in C++ programs */
38
#endif
39

40
#endif /*_IOCTRL_H*/

Bei dem extern "C" Aufruf bekomme ich folgende Fehlermeldung:
multiple definition of 'taskwrapper'

Der Task will einfach nicht starten...

Mfg
msimmerl
#3189394
Lesenswert?

Manuel Simmerl schrieb:


> extern "C" void taskwrapper(void* parm) {
>     (static_cast<ioCtrl*>(parm))->task();
> }


extern "C" inline void taskwrapper(void* parm) {
     (static_cast<ioCtrl*>(parm))->task();
}

Das inline ist wichtig. Denn sonst erzeugst du in jedem Cpp-File, 
welches dieses Header File includiert eine neue Funktion taskwrapper und 
es setzt einen ....
> Bei dem extern "C" Aufruf bekomme ich folgende Fehlermeldung:
> multiple definition of 'taskwrapper'



Edit:
Oder aber du ziehst die Funktion überhaupt in ioCtl.cpp hinein. Es gibt 
ja so wie es aussieht, sowieso keinen Grund, warum die im Header File 
sein sollte. Ist wahrscheinlich sowieso die bessere Lösung.
#3189564
Lesenswert?

Mich macht zum Beispiel stutzig, dass du eine 0 für den Pointer zum 
TaskHandle übergibst. Die Doku erwähnt nicht, dass dies zulässig ist.

Auch solltest du dir angewöhnen, ReturnCodes der Funktion aufzufangen 
und auszuwerten. xTaskCreate liefert einen Code, ob die Funktion 
geklappt hat oder nicht.

Und deine letzten beiden Parameter im Aufruf sind mir da ehrlich gesagt 
etwas zuviel gecastet. Das sollte eigentlich nicht notwendig sein.

Die Funktionssignatur
http://www.freertos.org/a00125.html
lautet
1
portBASE_TYPE xTaskCreate( 
2
                            pdTASK_CODE pvTaskCode, 
3
                            const portCHAR * const pcName, 
4
                            unsigned portSHORT usStackDepth, 
5
                            void *pvParameters, 
6
                            unsigned portBASE_TYPE uxPriority, 
7
                            xTaskHandle *pvCreatedTask 
8
                          );

da jetzt einfach eine 1 bzw eine 0 zu casten, ist meiner Meinung nach 
etwas gewagt. Und wie gesagt: ob die 0 überhaupt zulässig ist .....
(Firma: S+S) #3189579
Lesenswert?

So habs jetzt nochmals angepasst:
1
/* INCLUDE FILES **************************************************************/
2

3
/* IMPORT */
4
#include "common.h"
5
/* FreeRTOS */
6

7
#if defined(__cplusplus)
8
extern "C" {     /* Make sure we have C-declarations in C++ programs */
9
#endif
10

11
#include "FreeRTOS.h"
12
#include "task.h"
13
#include "queue.h"
14
#include "timers.h"
15

16
#include "ioCtrl.h"
17
#if defined(__cplusplus)
18
}     /* Make sure we have C-declarations in C++ programs */
19
#endif
20

21
/* EXPORT */
22

23
xTaskHandle xHandle;
24

25
extern "C" void taskwrapper(void* parm) {
26
    (static_cast<ioCtrl*>(parm))->task();
27
}
28

29
void ioCtrl::task(void)
30
{
31
  vErrorMessage( "Task is starting!", 0, RADIX_NO_VALUE, 0 );
32
  portTickType xLastWakeTime;
33
    xLastWakeTime = xTaskGetTickCount();
34

35
    for(;;) 
36
        {    
37
    vErrorMessage( "Task is running!", 0, RADIX_NO_VALUE, 0 );
38
      //Delay für 1000ms
39
      vTaskDelayUntil(&xLastWakeTime, ( 1000 / portTICK_RATE_MS ) );
40
    }
41
}
42

43
int ioCtrl::start(void)
44
{
45
  vErrorMessage( "Create task!", 0, RADIX_NO_VALUE, 0 );
46
  xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, NULL, CONTROL_TASK_PRIORITY, &xHandle);
47
}

Nur leider nach wie vor ohne Erfolg...

Habe den Rückgabewert überprüft von xTaskCreate. Der besagt, dass der 
Task erfolgreich angelegt wurde.
#3189602
Lesenswert?

Manuel Simmerl schrieb:

>   xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, NULL,
> CONTROL_TASK_PRIORITY, &xHandle);


Wieso NULL?


Dieses Argument hier

 xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, NULL,
                                                            ****

das ist das, welches die Funktion taskwrapper hier

extern "C" void taskwrapper(void* parm) {

                                 *******

wieder bekommt!
Wie willst du denn einen NULL Pointer vernünftig

    (static_cast<ioCtrl*>(parm))->task();

auf einen ioCtrl Pointer umcasten um damit dann die Memberfunktion 
dieses Objektes aufzurufen?

(Hast du eigentlich schon mal probiert, ob diese Verteiler-Funktion 
überhaupt aufgerufen wird?)

Aber abgesehen davon: Ich hab kein FreeRTOS da und auch keine Hardware 
auf der ich das probieren könnte. D.h. ich muss mich da jetzt sowieso 
verabschieden.
(Firma: S+S) #3190254
Lesenswert?

Erstmal vielen Dank für eure Hilfe.

Ich hätte schon versucht ob die Verteilerfunktion aufgerufen wird. 
Leider wird der Wrapper nie aufgerufen.

Das mit NULL als Parameterübergabe beim Task erstellen müsste eigentlich 
funktionieren. Zumindest wird das in der Doku, bei den Beispielen, auch 
so gemacht.

Irgendwas muss noch am dem Wrapper falsch sein denke ich...
#3190264
Lesenswert?

Manuel Simmerl schrieb:
> Das mit NULL als Parameterübergabe beim Task erstellen müsste eigentlich
> funktionieren.

Nein. Du dereferenzierst einen Nullzeiger. Wie Karl Heinz schon 
geschrieben hat, wird das, was du da an xTaskCreate übergibst, als 
Parameter an taskwrapper übergeben. Das heißt, param ist in taskwrapper 
NULL und das dereferenzierst du dann hier:
1
 (static_cast<ioCtrl*>(parm))->task();

> Zumindest wird das in der Doku, bei den Beispielen, auch so gemacht.

Wird da der Zeiger denn nacher auch benutzt, so wie bei dir?
Oder warum sollte das
1
extern "C" void taskwrapper(void* parm) {
2
                                  ^^^^

auf dein Objekt zeigen? Magie?
(Firma: S+S) #3190272
Lesenswert?

Jetzt noch ein anderer Ansatz.
Den wrapper brauch ich ja nur wenn ich auf eine Methode der Klasse 
verweisen möchte.

Jetzt mal für einen Versuch kann ich ja auch auf eine andere Methode 
verweisen.

void test(void *parm)
{
  vErrorMessage( "Task is starting!", 0, RADIX_NO_VALUE, 0 );
  portTickType xLastWakeTime;
    xLastWakeTime = xTaskGetTickCount();

    for(;;) {
    vErrorMessage( "Task is running!", 0, RADIX_NO_VALUE, 0 );
              //Delay für 1000ms
              vTaskDelayUntil(&xLastWakeTime, ( 1000 / portTICK_RATE_MS 
) );
        }
}


Nur komischerweise funktioniert nicht mal das....
#3190394
Lesenswert?

Manuel Simmerl schrieb:
> Jetzt noch ein anderer Ansatz.
> Den wrapper brauch ich ja nur wenn ich auf eine Methode der Klasse
> verweisen möchte.

Genau.
Weil du irgendwie die Kurve von der C Welt in die Welt der Objekte 
kratzen musst. Und das geht halt nur dann, wenn man irgendeinen Verweis 
auf ein Objekt hat.

> Jetzt mal für einen Versuch kann ich ja auch auf eine andere Methode
> verweisen.

Weise Entscheidung.
Genau so macht man das: Wenn nichts geht - abspecken, vereinfachen - bis 
man zum Kern des Problems vorstösst.

> Nur komischerweise funktioniert nicht mal das....

Womit wir wieder bei den Demos wären, die ja laut deiner Aussage 
funktionieren.
Also: Was ist bei den Demos anders?
Das können durchaus auch irgendwelche Compiler-Einstellungen sein!
(Firma: S+S) #3190558
Lesenswert?

Was mir noch aufgefallen ist, dass ich lauter Warnungen bekomme:

Phase Linker starting
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-closer.o):  In function `_close_r':
closer.c:(.text._close_r+0x10): warning: _close is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-fstatr.o):  In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x12): warning: _fstat is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-signalr.o):  In function `_getpid_r':
signalr.c:(.text._getpid_r+0x1): warning: _getpid is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-isattyr.o):  In function `_isatty_r':
isattyr.c:(.text._isatty_r+0x10): warning: _isatty is not implemented 
and will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-signalr.o):  In function `_kill_r':
signalr.c:(.text._kill_r+0x12): warning: _kill is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-lseekr.o):  In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x14): warning: _lseek is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-readr.o):  In function `_read_r':
readr.c:(.text._read_r+0x14): warning: _read is not implemented and will 
always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libstdc++.a 
(pure.o):  In function `__cxa_pure_virtual':
pure.cc:(.text.__cxa_pure_virtual+0xc): warning: _write is not 
implemented and will always fail


kann damit vielleicht jemand etwas anfangen?
Persönliche Seite #3191171
Lesenswert?

Wieder mal ein klassischer Fall von: am Symptom 'rumgedoktort ;-)
Karl Heinz ist sicherlich davon ausgegangen, dass Du solche fatalen 
Fehlermeldungen ganz sicher nicht (mehr) bekommst!

Eine Lösung habe ich da jetzt auch nicht zu, aber evtl. hilft die 
Compiler, oder genauer: die libc-Doku dabei, diese Fehler zu beheben. 
Dir fehlen die gesamten "reentrant functions", wie das bei der newlib in 
der Regel auch der Fall ist. Aber evtl. hilft da auch irgend ein 
Schalter, der die Verwendung abschaltet. Der newlib-Port für WinARM ist 
lange her...

Viel Erfolg!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren