#include "AUDIO.h"
#include "cy_dma.h"
#include "cy_gpio.h"
#include "cy_scb_spi.h"
#include "cy_tcpwm.h"
#include "cy_tcpwm_counter.h"
#include "cycfg_peripherals.h"

static uint8_t *buffer;
static size_t bufferRemaining;

static uint8_t transaction[3];

static cy_stc_scb_spi_context_t spiCtx;

void AUDIO_Init() {
	cy_rslt_t cyStatus;

	NVIC_ClearPendingIRQ(scb_2_interrupt_IRQn);
	NVIC_EnableIRQ(scb_2_interrupt_IRQn);

	cyStatus = Cy_SCB_SPI_Init(SCB2, &scb_2_config, &spiCtx);
	CY_ASSERT(cyStatus == CY_RSLT_SUCCESS);
	Cy_SCB_SPI_SetActiveSlaveSelect(SCB2, CY_SCB_SPI_SLAVE_SELECT1);
	Cy_SCB_SPI_Enable(SCB2);
    
	// SW reset
	transaction[0] = 0x51;
	transaction[1] = 0;
	transaction[2] = 0;
	cyStatus = Cy_SCB_SPI_Transfer(SCB2, transaction, NULL, 3, &spiCtx);
	CY_ASSERT(cyStatus == 0);
	cyStatus = cyhal_system_delay_ms(1);
	CY_ASSERT(cyStatus == CY_RSLT_SUCCESS);

    // power on DAC channel A
	transaction[0] = 0x40;
	transaction[1] = 0x01;
	transaction[2] = 0;
	cyStatus = Cy_SCB_SPI_Transfer(SCB2, transaction, NULL, 3, &spiCtx);
	CY_ASSERT(cyStatus == 0);
	cyStatus = cyhal_system_delay_ms(1);
	CY_ASSERT(cyStatus == CY_RSLT_SUCCESS);

	// select internal reference 2.0V
	transaction[0] = 0x75;
	transaction[1] = 0;
	transaction[2] = 0;
	cyStatus = Cy_SCB_SPI_Transfer(SCB2, transaction, NULL, 3, &spiCtx);
	CY_ASSERT(cyStatus == 0);
	cyStatus = cyhal_system_delay_ms(1);
	CY_ASSERT(cyStatus == CY_RSLT_SUCCESS);

}

void AUDIO_PlayAtBackground(uint8_t *data, size_t size) {
	buffer = (uint8_t *)data;
	bufferRemaining = size;

	NVIC_ClearPendingIRQ(tcpwm_0_interrupts_0_IRQn);
	NVIC_EnableIRQ(tcpwm_0_interrupts_0_IRQn);

	cy_rslt_t cyStatus = Cy_TCPWM_Counter_Init(
		tcpwm_0_cnt_0_HW, tcpwm_0_cnt_0_NUM, &tcpwm_0_cnt_0_config);
	CY_ASSERT(cyStatus == CY_RSLT_SUCCESS);
	Cy_TCPWM_Counter_Enable(tcpwm_0_cnt_0_HW, tcpwm_0_cnt_0_NUM);
	Cy_TCPWM_TriggerStart_Single(tcpwm_0_cnt_0_HW, tcpwm_0_cnt_0_NUM);
}

void scb_2_interrupt_IRQHandler(void) { Cy_SCB_SPI_Interrupt(SCB2, &spiCtx); }

void tcpwm_0_interrupts_0_IRQHandler(void) {
	Cy_TCPWM_ClearInterrupt(TCPWM0, 0, CY_TCPWM_INT_ON_TC);

	Cy_GPIO_Inv(GPIO_PRT9, 7);

	if (bufferRemaining) {

        int val = *((int16_t*)buffer) + 32768;
        uint16_t val16 = (uint16_t)val;

		transaction[0] = 0x20;
		transaction[2] = val16 & 0xFF;
		transaction[1] = val16 >> 8;
		bufferRemaining -= 2;
        buffer += 2;

		cy_en_scb_spi_status_t cyStatus =
			Cy_SCB_SPI_Transfer(SCB2, transaction, NULL, 3, &spiCtx);
		CY_ASSERT(cyStatus == 0);
	} else {
		Cy_TCPWM_TriggerStopOrKill_Single(TCPWM0, 0);
		Cy_TCPWM_Disable_Single(TCPWM0, 0);
	}
}