// Definisi Nilai Task Priority
#define PROCESS_TASK_PRIORITY 1
#define SERIAL_TASK_PRIORITY 2
// Definisi Nilai Pin LED untuk ESP32
#define LED_PIN LED_BUILTIN
// Variabel Interval waktu untuk setiap LED kedip
static int LED_Interval = 500;
// Queue Handler untuk Command dan Serial Output
QueueHandle_t xQueueCommand;
QueueHandle_t xQueueSerialOutput;
// Structure with variabel id and value
struct CommandStructure {
unsigned int body;
};
// Structure with variabel id and value
struct SerialStructure {
char body[128];
};
// Fungsi Input Serial monitor untuk membaca input dari Serial Monitoor
void vInputSerialMonitorTask(void *parameter) {
struct CommandStructure *pCommand; // Variabel pointer struct Command
struct SerialStructure *pSerial; // Variabel pointer struct Serial
while (1) { // Looping
// Check apabila menerima input dari Serial Monitor
if(Serial.available() > 0){
// Membaca string dari Serial Monitor hingga end line
String data = Serial.readStringUntil('\n');
int number = data.toInt(); // Mengambil integer dari input
if(number > 0){
// Port malloc pointer Command
pCommand = (struct CommandStructure *)pvPortMalloc(sizeof(struct CommandStructure));
pCommand->body = number; // Menempatkan angka pada body Command
if (xQueueSend(xQueueCommand, &pCommand, portMAX_DELAY) != pdPASS)
{
Serial.println("Failed to post to queue");
vPortFree(pCommand); // Free memory if message could not be sent to the queue
}
}
else{
// Port malloc pointer Serial Output
pSerial = (struct SerialStructure *)pvPortMalloc(sizeof(struct SerialStructure));
strcpy(pSerial->body, "Number is lower than 0 or Invalid Input"); // Menempatkan string error pada body Serial Output
if (xQueueSend(xQueueSerialOutput, &pSerial, portMAX_DELAY) != pdPASS)
{
Serial.println("Failed to post to queue");
vPortFree(pSerial); // Free memory if message could not be sent to the queue
}
}
}
// Delay kecil untuk menghindar busy-wait
vTaskDelay(pdMS_TO_TICKS(10)); // Delay 10 ms
}
}
// Fungsi Process Task dimana akan kedip berdasarkan variable LED_Interval
void vProcessTask(void *parameter) {
bool turnLEDOn = true; // Bool digunakan untuk toggle nilai LED
struct CommandStructure *pCommand; // Variabel pointer struct Command
TickType_t xLastWakeTime = xTaskGetTickCount(); // Untuk mendapatkan jumlah tick sebelumnya
while (1) { // Looping
// Menyalakan atau matikan LED
digitalWrite(LED_PIN, turnLEDOn);
// Toggle nilai bool LED
turnLEDOn = !turnLEDOn;
// Untuk dilakukan periode task ini berdasarkan interval LED_Interval
vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( LED_Interval ) );
// Check jika antrian tidak kosong dan terima data
if (xQueueReceive(xQueueCommand, &pCommand, 0) != errQUEUE_EMPTY)
{
LED_Interval = pCommand->body; // Menerima data dari antrian command
Serial.print("\nData Received from Command Queue : \n");
Serial.println((String)"LED Interval = " + LED_Interval); // Menampilkan data yang diterima
vPortFree(pCommand); // Free memory
}
}
}
void vOutputSerialMonitorTask(void *parameter){
struct SerialStructure *p; // Variabel pointer struct Serial
while (1)
{
// Check jika menerima data dari antrian Serial
if (xQueueReceive(xQueueSerialOutput, &p, 0))
{
Serial.print("\nData Received from Serial Queue : \n");
Serial.println(p->body); // Menampilkan error dari antrian Serial
vPortFree(p); // Free Memory
}
// Delay kecil untuk menghindar busy-wait
vTaskDelay(pdMS_TO_TICKS(10)); // Delay 10 ms
}
}
// Setup
void setup() {
// Set Baud Rate to 9600
Serial.begin(9600);
// Pin LED ESP32 dijadikan sebagai output
pinMode(LED_PIN, OUTPUT);
xQueueCommand = xQueueCreate(10, sizeof(struct CommandStructure*));
xQueueSerialOutput = xQueueCreate(10, sizeof(struct SerialStructure*));
// Error Handling if xQueueCommand atau xQueueSerialOutput is NULL
if (xQueueCommand == NULL || xQueueSerialOutput == NULL)
{
Serial.println("Error creating the queue");
}
// Create Process Queue Task
xTaskCreatePinnedToCore(
vProcessTask,
"vProcessTask",
10000, /* Stack size in words */
NULL, /* Task input parameter */
PROCESS_TASK_PRIORITY, /* Priority of the task */
NULL, /* Task handle. */
1 /* Core where the task should run */
);
// Create Input Serial Monitor Queue Task
xTaskCreatePinnedToCore(
vInputSerialMonitorTask,
"vInputSerialMonitorTask",
10000, /* Stack size in words */
NULL, /* Task input parameter */
SERIAL_TASK_PRIORITY, /* Priority of the task */
NULL, /* Task handle. */
1 /* Core where the task should run */
);
// Create Output Serial Monitor Queue Task
xTaskCreatePinnedToCore(
vOutputSerialMonitorTask,
"vOutputSerialMonitorTask",
10000, /* Stack size in words */
NULL, /* Task input parameter */
SERIAL_TASK_PRIORITY, /* Priority of the task */
NULL, /* Task handle. */
1 /* Core where the task should run */
);
// Delete Task
vTaskDelete(NULL);
}
// Loop
void loop() {
// Do Nothing
}