FreeRTOS CPP Function Pointer - c++

I want to use a member function of a CPP Class for a FreeRTOS taskFunction.
Here is my initial solution
#ifndef TaskCPP_H
#define TaskCPP_H
#include "FreeRTOS.h"
#include "task.h"
template<typename T>
class TaskBase {
protected:
xTaskHandle handle;
void run() {};
public:
static void taskfun(void* parm) {
static_cast<T*>(parm)->run();
#if INCLUDE_vTaskDelete
vTaskDelete(static_cast<T*>(parm)->handle);
#else
while(1)
vTaskDelay(10000);
#endif
}
virtual ~TaskBase() {
#if INCLUDE_vTaskDelete
vTaskDelete(handle);
#endif
return;
}
};
#endif /* __TaskCPP_H__ */
#ifndef HTTPSERVER_H_
#define HTTPSERVER_H_
#include "TaskBase.h"
#include <string.h>
#include "lwip/opt.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
#include "lwip/ip_addr.h"
class HttpServer;
class HttpServer : public TaskBase<HttpServer> {
public:
HttpServer();
virtual ~HttpServer();
void run();
void listen(ip_addr *address, uint8_t port);
void print();
protected:
char taskName[50];
ip_addr address;
uint8_t port;
};
#endif /* HTTPSERVER_H_ */
#include "HttpServer.h"
HttpServer::HttpServer()
{
}
void HttpServer::listen(ip_addr *address, uint8_t port) {
char buf[16];
sprintf(taskName, "%s_%d\r\n", ipaddr_ntoa_r(address, buf, 16), port);
DEBUGOUT("ADDRESS Listen: %x\r\n", &taskName);
this->handle = sys_thread_new(this->taskName, &taskfun, NULL, DEFAULT_THREAD_STACKSIZE + 128, DEFAULT_THREAD_PRIO);
}
void HttpServer::run() {
while(1) {
print();
Board_LED_Toggle(LEDS_LED2);
vTaskDelay(configTICK_RATE_HZ / 14);
}
}
void HttpServer::print() {
DEBUGOUT("ADDRESS Listen: %x\r\n", &taskName);
}
HttpServer::~HttpServer() {
// TODO Auto-generated destructor stub
}
Now my Problem ist that the context is not the same inside the run function. Printing the memory location of taskName is different inside listen(...) and run(...)
My nasty suspicion is that doing a static_cast of the run function looses the class context? Am I wrong?
Is there any other idea to provide a static function pointer to freeRTOS of a Class member function?
Here are the missing functions. The main and the sys_thread_new which is a wrapper only.
int main(void) {
prvSetupHardware();
HttpServer server;
server.listen(IP_ADDR_ANY, 80);
/* Start the scheduler */
vTaskStartScheduler();
/* Should never arrive here */
return 1;
}
sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority )
{
xTaskHandle xCreatedTask;
portBASE_TYPE xResult;
sys_thread_t xReturn;
xResult = xTaskCreate( pxThread, ( signed char * ) pcName, iStackSize, pvArg, iPriority, &xCreatedTask );
if( xResult == pdPASS )
{
xReturn = xCreatedTask;
}
else
{
xReturn = NULL;
}
return xReturn;
}

I use something like this:
class MyClass{
public:
static void run( void* pvParams ){
((MyClass*)pcParams)->runInner();
}
void runInner(){
while ( true ){
// TODO code here
}
}
};
then pass pointer to an object when creating task
MyClass* x = new MyClass;
xTaskCreate( MyClass::run, taskName, stackDepth, (void*) x, taskPrio, taskHandle );
edit:
Assuming you want to use templates:
template<typename T>
void run ( T* p ){
((T*)p)->run();
}
class MyClass{
public:
void run(){
while ( true ){
// task code
}
}
}
then creating the task
MyClass* x = new MyClass;
xTaskCreate( run<MyClass>, taskName, stackDepth, x, taskPrio, taskHandle );
Edit:
You need to cast run to (void (*)(void*))
xTaskCreate( (void (*)(void*))run<MyClass>, taskName, stackDepth, x, taskPrio, taskHandle );

Related

How do i pass a reference to a method through as a parameter

How do i pass a reference to a method through as a parameter? It might look something like this:
class Test
{
public:
Test();
void Bark();
void Bark2();
void TakesABark( void( &method )() );
}
// Start of procedure
Test::Test()
{
this->TakesABark(Test::Bark);
this->TakesABark(Test::Bark2);
}
void Test::Bark()
{
}
void Test::Bark2()
{
}
// Receives a variety of references to methods
void Test::TakesABark( void( &method )() )
{
// Calls a third party api that would look like this:
// Barbera::DoThatThingILike(Test::Bark2);
}
class Test
{
public:
Test();
void Bark();
void TakesABark(void (Test::*method)());
};
Test::Test()
{
this->TakesABark(&Test::Bark);
}
Sample code :
http://coliru.stacked-crooked.com/a/9351a79c20097035
#include <iostream>
#include <string>
#include <vector>
class Test
{
public:
Test();
void Bark();
void TakesABark( void(Test::*method)() );
};
Test::Test()
{
this->TakesABark(&Test::Bark);
}
void Test::Bark()
{
std::cout << "Bark";
}
void Test::TakesABark( void(Test::*method)() )
{
(this->*method)();
}
int main()
{
Test t;
}

Call member function of an object using pthread

How can I call the thread_ready_function into a thread as commented, using pthread ? I need to call it with the class object (In the real world the function uses attributes previously set).
MWE
#include <iostream>
#include <pthread.h>
class ClassA
{
public:
void * thread_ready_function(void *arg)
{
std::cout<<"From the thread"<<std::endl;
pthread_exit((void*)NULL);
}
};
class ClassB
{
ClassA *my_A_object;
public:
void test(){
my_A_object = new ClassA();
my_A_object->thread_ready_function(NULL);
// my_A_object->thread_ready_function(NULL);
// ^
// I want to make that call into a thread.
/* Thread */
/*
pthread_t th;
void * th_rtn_val;
pthread_create(&th, NULL, my_A_object.thread_ready_function, NULL);
pthread_join(th, &th_rtn_val);
*/
}
};
int main()
{
ClassB *my_B_object = new ClassB();
my_B_object->test();
return 0;
}
if you don't want to use C++11 or stl or boost, you must use the static key word for your member function,so that the pthread can call your member function!
example code:
#include <iostream>
#include <pthread.h>
using namespace std;
class A{
public:
static void* thread(void* args);
int parella_thread(int thread_num);
};
void* A::thread(void* args)
{
cout<<"hello world"<<endl;
}
int A::parella_thread(int thread_num)
{
pthread_t* thread_ids = new pthread_t[thread_num];
for(int i=0;i<thread_num;i++)
{
pthread_create(&thread_ids[i],NULL,thread,(void*)NULL);
}
delete[] thread_ids;
}
int main(int argc,char*argv[])
{
A test;
test.parella_thread(4);
return 0;
}

c++/CLI wrapper for pointer member - c++ singleton instance

I am completing my c++/CLI wrapper for the following native c++ class:
#ifndef __TV3DENGINE_H__
#define __TV3DENGINE_H__
#pragma once
#include "TV3DMoteur.h"
#include "Input.h"
#include "Area.h"
#include <vcclr.h>
class Engine3D
{
public:
CLTV3DMoteur* clTV3D;
CLInput* clInput;
CLArea* clArea;
CLGlobalVar * clGlobalVar;
Engine3D();
~Engine3D();
void Setup(HWND TVScreenHWND, string PathString);
void UpdateLoop();
void Cleanup();
bool AppStillIdle();
CLTV3DMoteur* GetTV3D();
CLInput* GetInput();
CLArea* GetArea();
CLGlobalVar * GetGlobalVar();
};
#endif
The actual constructor for Engine3D is :
Engine3D::Engine3D()
{
clTV3D = CLTV3DMoteur::getInstance();
clInput = CLInput::getInstance();
clArea = CLArea::getInstance();
clGlobalVar = CLGlobalVar::getInstance();
}
Here is the actual wrapper:
#ifndef __WRAPPER_H__
#define __WRAPPER_H__
#pragma once
#include "TV3DEngine.h"
#include <msclr\marshal_cppstd.h>
public ref class Engine3DWrapper {
Engine3D* m_nativeClass;
public:
Engine3DWrapper() { m_nativeClass = new Engine3D(); }
~Engine3DWrapper() { delete m_nativeClass; }
void Setup(System::IntPtr tvscreen, System::String^ AppPath) {
System::String^ managedPath = AppPath;
m_nativeClass->Setup((HWND)tvscreen.ToInt32(), msclr::interop::marshal_as<std::string>(managedPath));
}
void UpdateLoop() {
m_nativeClass->UpdateLoop();
}
void Cleanup() {
m_nativeClass->Cleanup();
}
bool AppStillIdle() {
return(m_nativeClass->AppStillIdle());
}
protected:
!Engine3DWrapper() { delete m_nativeClass; }
};
#endif
My question is how can I modifiy my Wrapper so I can have access to, exemple, Engine3DWrapper->clGlobalVar->BLABLABLA() where BLABLABLA would be all the different methods defined in the CLGlobalVar c++singleton?
I tried via this technique :
property String ^Name
{
String ^get()
{
return gcnew String(_stu->getName());
}
}
but that seems not possible since I need not to return a defined type.
thanks for your help.
Problem solved.
Here is the corrected Wrapper following Rufflewind suggestion:
#ifndef __WRAPPER_H__
#define __WRAPPER_H__
#pragma once
#include "TV3DEngine.h"
#include <msclr\marshal_cppstd.h>
public ref class Engine3DWrapper {
Engine3D* m_nativeClass;
public:
Engine3DWrapper(System::IntPtr tvscreen, System::String^ AppPath)
{
m_nativeClass = new Engine3D((HWND)tvscreen.ToInt32(), msclr::interop::marshal_as<std::string>(AppPath));
m_TV3D = m_nativeClass->GetTV3D();
m_Input = m_nativeClass->GetInput();
m_Area = m_nativeClass->GetArea();
m_GlobalVar = m_nativeClass->GetGlobalVar();
}
~Engine3DWrapper() {
delete m_nativeClass;
}
void UpdateLoop() {
m_nativeClass->UpdateLoop();
}
void Cleanup() {
m_nativeClass->Cleanup();
}
bool AppStillIdle() {
return(m_nativeClass->AppStillIdle());
}
CLTV3DMoteur* m_TV3D;
CLInput* m_Input;
CLArea* m_Area;
CLGlobalVar* m_GlobalVar;
protected:
!Engine3DWrapper() { delete m_nativeClass; }
};
#endif
using simple Get Method in the native class:
CLGlobalVar *Engine3D::GetGlobalVar()
{
clGlobalVar = CLGlobalVar::getInstance();
return(clGlobalVar);
}
Thanks for you help!

C++ preprocessor directive issue

I have a stream class with following functions :
void writeInt(int value); //old function
void writeInt(int value, char* lable); //new function
we've used the writeInt() old function in lot of places. without changing the existing usage
I tried to replace the old function with the new function using following:
#define writeInt(x) writeInt(x,#x)
but it still calls the old functions not the new functions!.
Update:(working test-case)
// IStream.h
#include <stdio.h>
class IWStream {
public:
IWStream(char* path);
virtual ~IWStream();
virtual void writeInt( int iValue, char* szlable= 0 );
private:
FILE* _file;
};
//DataObject.h
class DataObject {
public:
DataObject(int value);
virtual ~DataObject(){};
void writeData(IWStream *stream);
private:
int _value;
};
//DataObject.cpp
#include "DataObject.h"
#include "IStream.h"
#define writeInt(x) writeInt(x,#x)
DataObject::DataObject(int value)
{
_value = value;
}
void DataObject::writeData(IWStream *stream)
{
stream->writeInt(_value);
}
//main.cpp
int main(){
IWStream stream("D://test.txt");
DataObject data(10);
data.writeData(&stream);
return 0;
}

Export observer pattern from a c++ library in c code

I have a c++ shared library that can generate some event. I've an interface for the listener and a class that is able to register observers and fire events.
This library may be used used from java, C# and C++ code( compiled with differenc compilers) so I've two file headers: *.h for ANSI C interface and *.hpp for use library directly from C++ code. Now I cannot figure how export observer pattern with a C-like interface.
Here is a little snippet of how code is structured.
// hpp file
class IListener
{
public:
virtual ~IListener() {}
virtual void event1( int ) = 0;
virtual void event2() = 0;
};
using IListenerPtr = std::shared_ptr< IListener >;
class Controller
{
public:
Controller( IListenerPtr listener );
void addListener( IListenerPtr listener );
private:
void threadFunc()
{
while ( true )
{
// an event occured
for ( auto& e : mListeners )
e->event1( 2 );
for ( auto& e : mListeners )
e->event2();
}
}
private:
std::vector< IListenerPtr > mListeners;
};
// h file
#if defined( __MSCVER ) || defined( __MINGW32__ ) || defined( __MINGW64__ )
# define LIB_CALLBACK __stdcall
# define LIB_CALL __cdecl
# if defined( AAMS_EXPORTS )
# define LIB_API __declspec( dllexport )
# else
# define LIB_API __declspec( dllimport )
# endif
#else
# define LIB_API
#endif // WIN32
typedef int libError;
LIB_API libError LIB_CALL libInit( ???? );
How can I make this library usable from C code? A first attempt maybe:
typedef struct libListenerTag
{
typedef void (LIB_CALLBACK *Event1Func)( int );
typedef void (LIB_CALLBACK *Event2Func)();
Event1Func Event1;
Event2Func Event2;
} libListener;
LIB_API libError LIB_CALL libInit( libListener* listener );
and in someway bind libListener to IListener
// cpp file
class CListener : public IListener
{
public:
CListener( libListener* listener
: mListener( listener )
{
}
void event1( int i ) { mListener->Event1( i ); }
void event2() { mListener->Event12(); }
private:
libListener* mListener;
}
Controller* g_controller = nullptr;
LIB_API libError LIB_CALL libInit( libListener* listener )
{
g_controller = new Controller( make_shared< CListener >( listener );
// ...
}
This method doesn't look very good for me. Is a better way to accomplish this?
You're missing something that's standard in C event callbacks: a context pointer.
In C++ your IListener subclass gets an implicit this pointer in its callbacks, meaning it can store state and context info in the instance.
For free functions, you don't have this, so you need to add an explicit argument.
/* c_interface.h */
typedef void (*EventCallback1)(void *context, int arg);
typedef void (*EventCallback2)(void *context);
struct Listener; /* opaque type */
struct Listener *create_listener(EventCallback1, EventCallback2, void *context);
void destroy_listener(struct Listener*);
so from the C side, you pack whatever state you need into a structure, pass it into create_listener as your context, and get it passed back to your functions when they're called.
// c_implementation.cpp
extern "C" {
#include "c_interface.h"
struct Listener: public IListener {
EventCallback1 cb1;
EventCallback2 cb2;
void *context;
Listener(EventCallback1 e1, EventCallback2 e2, void *c)
: cb1(e1), cb2(e2), context(c)
{}
virtual void event1(int arg) {
(*cb1)(context, arg);
}
virtual void event2() {
(*cb2)(context);
}
};
Listener *create_listener(EventCallback1 cb1, EventCallback2 cb2, void *context) {
return new Listener(cb1, cb2, context);
}
}
The client code looks something like
#include "c_interface.h"
struct MyContext {
int things;
double needed;
int to_handle;
char callbacks[42];
};
void cb0(void *context) {}
void cb1(void *context, int arg) {
struct MyContext *c = (struct MyContext *)context;
c->things = arg;
}
void foo() {
struct MyContext *context = malloc(sizeof(*context));
struct Listener *l = create_listener(cb1, cb0, context);
...