/*******************************************************************
File: waveplayer.c
Date: 29-September-2025
Author: Peter Spindler
Description: Functions to play a wave file. Requires functions from audio.c
 ********************************************************************/
#include "stm32f7xx_hal.h"
#include "audio.h"

#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"

#include "ff.h"
#include "fatfs.h"

#include "audio.h"
#include "gui.h"
#include "display.h"
#include <stdio.h>
#include <string.h>

#define BUTTON_PLUS 0
#define BUTTON_MINUS 1
#define BUTTON_PLAY 2
#define BUTTON_PAUSE 3
#define BUTTON_STOP 4

enum playerState {PAUSED, PLAYING, STOPPED} playerState = PLAYING;

FIL WaveFile;
#define AUDIO_BUFFER_SIZE_WORDS  (1024*8)
uint16_t Audio_Buffer[AUDIO_BUFFER_SIZE_WORDS];
#define PLAYER_NOTIFY_HALF   (1UL << 0)
#define PLAYER_NOTIFY_FULL   (1UL << 1)
static TaskHandle_t PlayerTaskHandle = NULL;


SemaphoreHandle_t Semphr_FillBuffer = NULL;
uint8_t fillFlag = 0;

// helper to update volume value on display
uint8_t volume = 70;
void drawVolume(){
		      Display_Printf( 0, 40,
		      		LCD_COLOR_WHITE, LCD_COLOR_BLACK,
		      		&FontBig,
		          "%03d", volume
		      );
}

void Player_Start( const char *Filename ) {
	FRESULT res;
	printf("debug: Player_Start opening file...\n");
	// FIXME: Currently is stuck / crashes here (when stopping, then playing again) ===================
	if( (res=f_open(&WaveFile, Filename , FA_READ )) != FR_OK) {
		printf("Error: Can't open audio file %s: %d\n", Filename, res);
		return;
	}
	printf("debug: Player_start finished opening file. \n");
	printf("Open wavefile %s: successful\n", Filename );

	Audio_SetFrequency(22050);

	// fill audio buffer completely
	UINT bytesRead = 0;
	res = f_read(&WaveFile, Audio_Buffer, sizeof(Audio_Buffer), &bytesRead);
	if( res != FR_OK ) {
		printf("Error: Can't read audio file %s: %d\n", Filename, res);
		f_close(&WaveFile);
		return;
	}

	Audio_Play( (uint8_t*) Audio_Buffer, sizeof(Audio_Buffer)/2 );
}

void Player_Stop( void ) {
    Audio_Stop();
	f_close(&WaveFile);
}

// Player_HalfTransfer_CallBack: called from DMA2_Stream4-ISR if first half of audio buffer has been transferred to SAI2
void Player_HalfTransfer_CallBack( void ) {
	fillFlag = 0;
	//printf("give 0\n");
	xSemaphoreGiveFromISR(Semphr_FillBuffer, NULL);
}

// Player_CompleteTransfer_CallBack: called from DMA2_Stream4-ISR if second half of audio buffer has been transferred to SAI2
void Player_CompleteTransfer_CallBack( void ) {
	fillFlag = 1;
	//printf("give 1\n");
	xSemaphoreGiveFromISR(Semphr_FillBuffer, NULL);
}

static void Player_Task( void *arguments ) {
	UINT bytesRead = 0;
	uint32_t notifyValue = 0;
	drawVolume();
	while(1) {
		// 1. fill audio buffer if requested 
    	if (xSemaphoreTake(Semphr_FillBuffer, pdMS_TO_TICKS(20))){
			if (playerState != PLAYING) continue;
			if (fillFlag == 0){ // half flag -> fill first half
				if( f_read(&WaveFile, &Audio_Buffer[0], sizeof(Audio_Buffer)/2, &bytesRead) != FR_OK ) {
					bytesRead = 0;
				}
				if( bytesRead < AUDIO_BUFFER_SIZE_WORDS/2 ) {
					printf("error reading bytes, stopping playback\n");
					Player_Stop();
					playerState = STOPPED;
				}
			}

			else if (fillFlag == 1){ // complete flag -> fill second half
				bytesRead = 0;
				if( f_read(&WaveFile, &Audio_Buffer[AUDIO_BUFFER_SIZE_WORDS/2], sizeof(Audio_Buffer)/2, &bytesRead) != FR_OK ) {
					bytesRead = 0;
				}
				if( bytesRead < AUDIO_BUFFER_SIZE_WORDS/2 ) {
					printf("error reading bytes, stopping playback\n");
					Player_Stop();
					playerState = STOPPED;
				}
			}
		}

		// 2. run player control (handle gui events)
	  	//printf("running player control...\n");
  		  uint8_t gui_msg = 0;
  		  if (xQueueReceive(GUIQueue, &gui_msg, pdMS_TO_TICKS(0))){
  		    printf("Received GUI event %d\n", gui_msg);

  		    switch(gui_msg){
  		      case BUTTON_PLUS:
  		        if (++volume > 100) volume = 100;
  		        drawVolume();
				Audio_SetVolume(volume);
  		      break;

  		      case BUTTON_MINUS:
  		        if (volume-- == 0) volume = 0;
  		        drawVolume();
				Audio_SetVolume(volume);
  		        break;

  		      case BUTTON_PLAY:
  		        printf("Play\r\n");
				if (playerState == STOPPED){
					printf("was stopped, starting player from start\n");
    				//	FATFS fs;
    				//	printf("1. mounting filesystem...\n");
    				//	f_mount(&fs, "/", 0);
					Player_Start("audio.wav");
				} else if (playerState == PAUSED){
					printf("was paused, resuming...\n");
					Audio_Resume();
				}
				playerState = PLAYING;
  		      break;

  		      case BUTTON_PAUSE:
  		        printf("Pausing\r\n");
				Audio_Pause();
				playerState = PAUSED;
  		      break;

  		      case BUTTON_STOP:
  		        printf("Stopping player\r\n");
				Player_Stop();
				playerState = STOPPED;
  		      break;
  		    }
  		  }
			vTaskDelay(pdMS_TO_TICKS(10));
	}
}

void Player_Init( void ) {
	portENABLE_INTERRUPTS(); // Workaround to re-enable interrupts after FreeRTOS functions
    // 70: initial volume, 44100: initial sampling frequency
	if( Audio_Init(OUTPUT_DEVICE_AUTO,70,44100) != AUDIO_OK ) {
		printf("Error: Can't init audio!\n");
	}
  	Semphr_FillBuffer = xSemaphoreCreateBinary();
	xTaskCreate(Player_Task,"Player", 512,NULL,0,&PlayerTaskHandle);
}
