Я хочу использовать функцию-член класса CPP для функции задачи FreeRTOS.
Вот мое первоначальное решение
#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
}
Теперь моя проблема заключается в том, что контекст не совпадает внутри функции запуска. Печать ячейки памяти taskName
отличается внутри listen(...)
а также run(...)
Мое неприятное подозрение, что выполнение static_cast из функции run приводит к потере контекста класса? Я ошибся?
Есть ли другая идея предоставить статический указатель на функцию freeRTOS функции-члена класса?
Вот недостающие функции. main
и sys_thread_new
который является только оберткой.
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;
}
Я использую что-то вроде этого:
class MyClass{
public:
static void run( void* pvParams ){
((MyClass*)pcParams)->runInner();
}
void runInner(){
while ( true ){
// TODO code here
}
}
};
затем передайте указатель на объект при создании задачи
MyClass* x = new MyClass;
xTaskCreate( MyClass::run, taskName, stackDepth, (void*) x, taskPrio, taskHandle );
редактировать:
Предполагая, что вы хотите использовать шаблоны:
template<typename T>
void run ( T* p ){
((T*)p)->run();
}
class MyClass{
public:
void run(){
while ( true ){
// task code
}
}
}
затем создать задачу
MyClass* x = new MyClass;
xTaskCreate( run<MyClass>, taskName, stackDepth, x, taskPrio, taskHandle );
Редактировать:
Вам нужно разыграть run
в (void (*)(void*))
xTaskCreate( (void (*)(void*))run<MyClass>, taskName, stackDepth, x, taskPrio, taskHandle );
Других решений пока нет …