//Eriqo Arief Wicaksono - 2106638406
// Mendefinisikan variabel global
bool isPlayed = false;
bool isPaused = false;
unsigned int counter = 0; //variabel untuk menyimpan waktu player
SemaphoreHandle_t mutex; // membuat handle mutex
//PENJELASAN STATE
// ====================================
// | isPlayed | isPaused | STATE |
// ====================================
// | FALSE | FALSE | STOP |
// | TRUE | FALSE |PLAY/RESUME|
// | TRUE | TRUE | PAUSE |
// | FALSE | TRUE |Tidak valid|
// ====================================
void vBluetoothInit(void *parameters){
TickType_t timestamp;
//Simulasi pekerjaan
Serial.println("Task Bluetooth mencoba mengambil mutex...");
timestamp = xTaskGetTickCount() * portTICK_PERIOD_MS;
xSemaphoreTake(mutex, portMAX_DELAY); //Percobaan mengambil mutex
Serial.print("Task Bluetooth mendapatkan mutex setelah menunggu ");
Serial.print((xTaskGetTickCount() * portTICK_PERIOD_MS) - timestamp);
Serial.println(" ms");
Serial.println("Connecting to bluetooth...");
vTaskDelay(2000 / portTICK_PERIOD_MS);
Serial.print("Bluetooth connected after ");
Serial.print((xTaskGetTickCount() * portTICK_PERIOD_MS) - timestamp);
Serial.println(" ms.");
xSemaphoreGive(mutex);
vTaskDelete(NULL);
}
void vTaskLED(void *parameters){
TickType_t timestamp;
while(1){
if (isPlayed && !isPaused) {
digitalWrite(LED_BUILTIN, HIGH);
}else if (!isPlayed) { //jika state == STOP
// Mematikan LED_BUILTIN
digitalWrite(LED_BUILTIN, LOW);
}
timestamp = xTaskGetTickCount() * portTICK_PERIOD_MS;
while ( (xTaskGetTickCount() * portTICK_PERIOD_MS) - timestamp < 2000);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
//Membuat fungsi callback yang akan dijalankan setiap timer berakhir
//Fungsi ini akan mengecek state dan melakukan print apabila state == PLAY
void vMusicPlayer(void *parameters) {
while(1){
//Mengecek current state, jika state == PLAY
if (isPlayed && !isPaused) {
// Menyalakan LED_BULTIN
// Menampilkan waktu pemutaran musik
Serial.print("Time: ");
Serial.printf("%02d:%02d / 05:00\n", counter / 60, counter % 60);
counter++; // Meng-increment waktu pemutaran
//jika waktu pemutaran sudah 300 detik (5 menit)
if (counter >= 300) {
// Mengubah state menjadi STOP
isPlayed = false;
//Mencetak keterangan ke serial monitor
Serial.println("Song finished. Player stopped");
}
} else if (!isPlayed) { //jika state == STOP
// Mematikan LED_BUILTIN
digitalWrite(LED_BUILTIN, LOW);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
//Task untuk mengontrol state pada program menggunakan nested if
void stateController(void *parameter){
TickType_t timestamp;
while(1){
timestamp = xTaskGetTickCount() * portTICK_PERIOD_MS;
xSemaphoreTake(mutex, portMAX_DELAY); //Percobaan mengambil mutex
if (Serial.available() > 0) { //Mengecek ketersediaan Serial Monitor
String command = Serial.readStringUntil('\n'); //Membaca serial monitor sampai \n
//Mengecek input
if (command == "Play") { //Jika inputnya Play
//Mengecek state
if (!isPlayed) {//Jika state == STOP
isPlayed = true; //Mengubah state ke PLAY
counter = 0; //Mengisi waktu pemutaran dengan 0
Serial.println("Playing song"); //Mencetak informasi ke Serial Monitor
} else { //Jika statenya bukan PLAY
//Mencetak pesan error ke Serial monitor
Serial.println("Error! Cannot \"Play\" at the moment.");
}
} else if (command == "Pause") { //Jika inputnya Pause
//Mengecek state
if (isPlayed && !isPaused) { //Jika statenya PLAY
isPaused = true; //Mengubah state menjadi PAUSE
// Mencetak informasi ke Serial Monitor
Serial.println("Player Paused, Timer Paused");
digitalWrite(LED_BUILTIN, LOW); //Mematikan LED
}else{// Jika statenya bukan PLAY
//Mencetak pesan error ke serial monitor
Serial.println("Error! Cannot \"Pause\" at the moment.");
}
} else if (command == "Resume") { //Juka inputnya Resume
//Mengecek state
if (isPlayed && isPaused) { //Jika statenya PAUSE
isPaused = false; //Mengubah state ke PLAY
// Mencetak informasi ke Serial Monitor
Serial.println("Player resumed. Timer resumed");
} else { //Jika statenya bukan PAUSE
//Mencetak pesan error ke serial monitor
Serial.println("Error! Cannot \"Resume\" at the moment.");
}
} else if (command == "Stop") { //Jika inputnya Stop
//Mengecek state
if(isPlayed || isPaused){ //Jika statenya PLAY atau PAUSE
//Mengubah state ke STOP
isPlayed = false;
isPaused = false;
counter = 0; // Me-reset timer
// Mencetak informasi ke Serial Monitor
Serial.println("Player Stopped. Timer resetted");
}else{ //Jika statenya bukan PLAY atau PAUSE
//Mencetak pesan error ke serial monitor
Serial.println("Error! Player is already stopped");
}
} else { //Jika inputnya bukan keempat case diatas
//Mencetak pesan error ke serial monitor
Serial.println("Invalid input");
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
xSemaphoreGive(mutex);
}
}
void setup() {
//Memulai serial
Serial.begin(115200);
// Mengatur pin LED sebagai output
vTaskDelay(1000 / portTICK_PERIOD_MS);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
mutex = xSemaphoreCreateMutex();
//Menjalankan task stateController yang sudah dibuat sebelumnya
xTaskCreatePinnedToCore(stateController, "Controller", 10000, NULL, 1, NULL, 1);
vTaskDelay(1 / portTICK_PERIOD_MS);
xTaskCreatePinnedToCore(vBluetoothInit, "Init BT", 10000, NULL, 3, NULL, 1);
xTaskCreatePinnedToCore(vTaskLED, "LED setter", 10000, NULL, 2, NULL, 1);
xTaskCreatePinnedToCore(vMusicPlayer, "Music Player", 10000, NULL, 2, NULL, 0);
//vTaskDelay(1 / portTICK_PERIOD_MS);
// Membuat software timer
//Menghapus task setup dan loop
vTaskDelete(NULL);
}
void loop() {
}