#include <Arduino_FreeRTOS.h>
#include <task.h>
#include <semphr.h>

// Semaphore handle
SemaphoreHandle_t xSemaphore;

// Task 1: Allocate memory
void Task1(void *pvParameters) {
    char *p;
    while (1) {
        // Wait for the semaphore to be free
        if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
            p = (char *)pvPortMalloc(100 * sizeof(char));
            if (p != NULL) {
                Serial.println("Memory allocated by Task 1");
                vPortFree(p);
            } else {
                Serial.println("Memory allocation failed by Task 1");
            }
            // Release the semaphore
            xSemaphoreGive(xSemaphore);
            // Delay for a while
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
}

// Task 2: Allocate memory
void Task2(void *pvParameters) {
    char *p;
    while (1) {
        // Wait for the semaphore to be free
        if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
            p = (char *)pvPortMalloc(100 * sizeof(char));
            if (p != NULL) {
                Serial.println("Memory allocated by Task 2");
                vPortFree(p);
            } else {
                Serial.println("Memory allocation failed by Task 2");
            }
            // Release the semaphore
            xSemaphoreGive(xSemaphore);
            // Delay for a while
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
}

void setup() {
    Serial.begin(115200);
    
    // Create the semaphore
    xSemaphore = xSemaphoreCreateMutex();
    if (xSemaphore != NULL) {
        // Create tasks
        xTaskCreate(Task1, "Task 1", 128, NULL, 1, NULL);
        xTaskCreate(Task2, "Task 2", 128, NULL, 1, NULL);
    }
    
    // Start the scheduler
    vTaskStartScheduler();
}

void loop() {
    // Do nothing
}