/*
  ESP32-S3 Dual-Core Demonstration
  
  Concept:
  - Core 1 ("The Worker"): Runs a 'blocking' and computationally intensive task.
    It will count to a large number and print its progress, simulating a heavy workload.
  - Core 0 ("The UI"): Runs a 'responsive' user interface task.
    It blinks the onboard LED and instantly responds to user input from the Serial Monitor.

  This demonstrates true parallel processing, as the responsive UI is not affected
  by the heavy task running on the other core.
*/

// Task handles are used to track our created tasks
TaskHandle_t workerTaskHandle;
TaskHandle_t uiTaskHandle;

// Define the built-in LED pin. For most ESP32-S3 boards, this is correct.
// Check your board's documentation if it doesn't work.
#ifndef LED_BUILTIN
  #define LED_BUILTIN 2 
#endif

// A variable to control the LED state from the UI task
bool ledState = true;

// --- Task 1: The "Heavy Worker" Code ---
// This function will be pinned to Core 1.
void workerTask(void *pvParameters) {
  Serial.print("Worker Task running on core ");
  Serial.println(xPortGetCoreID());

  unsigned long long counter = 0;
  while (true) {
    counter++;
    // To make the task "heavy" but not spam the serial port,
    // we'll only print every 1000 iterations.
    if (counter % 1000 == 0) {
      Serial.print("Worker Core 1: Still busy! Count: ");
      Serial.println(counter);
    }
    // A small delay to prevent watchdog timer issues, but the task is still very busy.
    // On a single core, this loop would make the system unresponsive.
    vTaskDelay(1);
  }
}


// --- Task 2: The "Responsive UI" Code ---
// This function will be pinned to Core 0.
void uiTask(void *pvParameters) {
  Serial.print("UI Task running on core ");
  Serial.println(xPortGetCoreID());

  pinMode(LED_BUILTIN, OUTPUT);
  long lastBlink = 0;

  while (true) {
    // 1. Handle user input (non-blocking)
    if (Serial.available() > 0) {
      String input = Serial.readString(); 
      input.trim(); // .trim() removes newline characters
      Serial.print("UI Core 0 Received: '");
      Serial.print(input); 
      Serial.println("' -> Acknowledged instantly!");
    }

    // 2. Handle the blinking LED (non-blocking)
    if (millis() - lastBlink > 500) {
      ledState = !ledState;
      digitalWrite(LED_BUILTIN, ledState);
      lastBlink = millis();
    }
    
    // Briefly yield to allow other system tasks on this core to run
    vTaskDelay(10); 
  }
}


// --- Standard Arduino Setup ---
void setup() {
  Serial.begin(115200);
  delay(1000); // Wait for Serial to initialize

  Serial.println("--- ESP32 Dual-Core Demo ---");
  Serial.println("Type anything into the Serial Monitor and press Enter.");
  Serial.println("You will see an instant response from Core 0,");
  Serial.println("while Core 1 continues its heavy calculation in the background.");
  Serial.println("------------------------------------");

  // Create the "Heavy Worker" task and pin it to Core 1
  xTaskCreatePinnedToCore(
      workerTask,        // Function to implement the task
      "WorkerTask",      // Name of the task
      10000,             // Stack size in words
      NULL,              // Task input parameter
      1,                 // Priority of the task
      &workerTaskHandle, // Task handle to keep track of created task
      1);                // Pin task to core 1

  // Create the "Responsive UI" task and pin it to Core 0
  xTaskCreatePinnedToCore(
      uiTask,            // Function to implement the task
      "UITask",          // Name of the task
      10000,             // Stack size in words
      NULL,              // Task input parameter
      1,                 // Priority of the task
      &uiTaskHandle,     // Task handle to keep track of created task
      0);                // Pin task to core 0
}


// --- Standard Arduino Loop ---
// The loop is empty because our tasks are managed by the FreeRTOS scheduler.
void loop() {
  // This is intentionally left empty.
  // The FreeRTOS scheduler is now in control.
  vTaskDelay(1000); 
}