//
// TaskWrapper.c
//
//
// Created by Chris Galzerano on 2/7/26.
//
#define _GNU_SOURCE // For core pinning
#include "TaskWrapper.h"
#include <stdio.h>
#include <stdlib.h>
// ==========================================
// ESP32 IMPLEMENTATION (Native vTaskDelete)
// ==========================================
#ifdef ESP_PLATFORM
// Internal wrapper to handle argument passing
typedef struct {
TaskFunction_t userFunc;
void *userArgs;
} EspArgs;
static void esp_task_entry(void *arg) {
EspArgs *p = (EspArgs *)arg;
p->userFunc(p->userArgs);
free(p);
vTaskDelete(NULL); // Suicide if function returns
}
TaskContext_t TaskStart(const char *name, uint32_t stackSize, int priority, TaskFunction_t taskFunc, void *args, int coreID) {
EspArgs *p = malloc(sizeof(EspArgs));
p->userFunc = taskFunc;
p->userArgs = args;
TaskHandle_t handle;
BaseType_t res;
if (coreID >= 0) {
res = xTaskCreatePinnedToCore(esp_task_entry, name, stackSize, p, priority, &handle, coreID);
} else {
res = xTaskCreate(esp_task_entry, name, stackSize, p, priority, &handle);
}
if (res != pdPASS) {
free(p);
return NULL;
}
return handle;
}
void TaskDelete(TaskContext_t task) {
if (task) {
vTaskDelete(task); // NATIVE ESP32 DELETE
}
}
bool TaskShouldExit(void) {
// On ESP32, vTaskDelete kills the task instantly.
// The code never reaches this check if it's dead.
return false;
}
void TaskDelay(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
}
// ==========================================
// LINUX IMPLEMENTATION (Flag + Join)
// ==========================================
#else
#include <unistd.h>
#include <sched.h>
#include <time.h>
struct LinuxTaskState {
pthread_t thread;
bool stopFlag;
TaskFunction_t userFunc;
void *userArgs;
};
// Thread-Local Storage to track current task context
static __thread struct LinuxTaskState* g_current_ctx = NULL;
static void *linux_thread_entry(void *arg) {
struct LinuxTaskState *ctx = (struct LinuxTaskState *)arg;
g_current_ctx = ctx; // Save context to TLS
ctx->userFunc(ctx->userArgs); // Run user code
return NULL;
}
TaskContext_t TaskStart(const char *name, uint32_t stackSize, int priority, TaskFunction_t taskFunc, void *args, int coreID) {
struct LinuxTaskState *ctx = malloc(sizeof(struct LinuxTaskState));
if (!ctx) return NULL;
ctx->stopFlag = false;
ctx->userFunc = taskFunc;
ctx->userArgs = args;
pthread_attr_t attr;
pthread_attr_init(&attr);
// 1. Scale Stack
size_t safeStack = (stackSize < 16384) ? 16384 : stackSize;
pthread_attr_setstacksize(&attr, safeStack);
// 2. Core Pinning
if (coreID >= 0) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(coreID, &cpuset);
pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
}
if (pthread_create(&ctx->thread, &attr, linux_thread_entry, ctx) != 0) {
free(ctx);
pthread_attr_destroy(&attr);
return NULL;
}
pthread_attr_destroy(&attr);
return ctx;
}
void TaskDelete(TaskContext_t task) {
if (!task) return;
// 1. Signal Stop
task->stopFlag = true;
// 2. Wait for graceful exit
pthread_join(task->thread, NULL);
// 3. Free Memory
free(task);
}
bool TaskShouldExit(void) {
if (g_current_ctx) {
return g_current_ctx->stopFlag;
}
return false;
}
void TaskDelay(uint32_t ms) {
struct timespec ts = { .tv_sec = ms / 1000, .tv_nsec = (ms % 1000) * 1000000 };
nanosleep(&ts, NULL);
}
#endif