/**
 * \file
 *
 * \brief SAM D20 DAC Sound Player Application
 *
 * Copyright (C) 2013 Atmel Corporation. All rights reserved.
 *
 * \license
 * \asf_license_start
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 *    Atmel microcontroller product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \asf_license_stop
 *
 */

/**
 * \mainpage SAM D20 DAC Sound Player Application
 * See \ref appdoc_main "here" for project documentation.
 * \copydetails appdoc_preface
 *
 *
 * \page appdoc_preface Overview
 * This application demonstrates a simple sound player, sourcing a waveform
 * from the device's Non-Volatile Memory and streaming it out of the DAC as
 * an analog waveform.
 */

/**
 * \page appdoc_main SAM D20 DAC Sound Player Application
 *
 * Overview:
 * - \ref appdoc_samd20_dac_sound_player_intro
 * - \ref appdoc_samd20_dac_sound_player_setup
 * - \ref appdoc_samd20_dac_sound_player_usage
 * - \ref appdoc_samd20_dac_sound_player_compinfo
 * - \ref appdoc_samd20_dac_sound_player_contactinfo
 *
 * \section appdoc_samd20_dac_sound_player_intro Introduction
 * This application demonstrates a simple sound player, sourcing a waveform
 * from the device's Non-Volatile Memory and streaming it out of the DAC as
 * an analog waveform.
 *
 * A timer is used to guarantee the DAC conversions are performed at the correct
 * sample rate, using the Event System module of the device to link the periodic
 * timer output events to the DAC module to trigger new sample conversions.
 *
 * \section appdoc_samd20_dac_sound_player_setup Hardware Setup
 * The device's DAC channel 0 output should be connected to an audio amplifier,
 * speaker, oscilloscope or other similar monitoring equipment so that the
 * generated waveform can be monitored.
 *
 * \section appdoc_samd20_dac_sound_player_usage Usage
 * On startup the device hardware will be configured, and the example will enter
 * an infinite loop. Each time the board button is pressed, the embedded
 * waveform will be output through the DAC and the board LED will be toggled
 *
 * \section appdoc_samd20_dac_sound_player_compinfo Compilation Info
 * This software was written for the GNU GCC and IAR for ARM.
 * Other compilers may or may not work.
 *
 * \section appdoc_samd20_dac_sound_player_contactinfo Contact Information
 * For further information, visit
 * <a href="http://www.atmel.com">http://www.atmel.com</a>.
 */

#include <asf.h>

/** Sample rate of the sound table. */
const uint32_t sample_rate = 16000;

/** Embedded waveform table of sound samples to output. */
const uint16_t wav_samples[] = {
	#include "data.x"
};

/** Number of samples in the waveform. */
const uint32_t number_of_samples =
		(sizeof(wav_samples) / sizeof(wav_samples[0]));


/**
 * \brief Configures the DAC in event triggered mode.
 *
 * Configures the DAC to use the module's default configuration, with output
 * channel mode configured for event triggered conversions.
 *
 * \param dev_inst  Pointer to the DAC module software instance to initialize
 */
static void configure_dac(struct dac_module *dac_module)
{
	struct dac_config config;
	struct dac_chan_config channel_config;

	/* Get the DAC default configuration */
	dac_get_config_defaults(&config);

	/* Switch to GCLK generator 0 */
	config.clock_source = GCLK_GENERATOR_0;

	dac_init(dac_module, DAC, &config);

	/* Get the default DAC channel config */
	dac_chan_get_config_defaults(&channel_config);

	/* Set the channel configuration, and enable it */
	dac_chan_set_config(dac_module, DAC_CHANNEL_0, &channel_config);
	dac_chan_enable(dac_module, DAC_CHANNEL_0);

	/* Enable event triggered conversions */
	struct dac_events events = { .on_event_start_conversion = true };
	dac_enable_events(dac_module, &events);

	dac_enable(dac_module);
}

/**
 * \brief Configures the TC to generate output events at the sample frequency.
 *
 * Configures the TC in Frequency Generation mode, with an event output once
 * each time the audio sample frequency period expires.
 *
 * \param dev_inst  Pointer to the TC module software instance to initialize
 */
static void configure_tc(struct tc_module *tc_module)
{
	struct tc_config config;
	tc_get_config_defaults(&config);

	config.clock_source    = GCLK_GENERATOR_0;
	config.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;

	tc_init(tc_module, TC0, &config);

	/* Enable periodic event output generation */
	struct tc_events events = { .generate_event_on_overflow = true };
	tc_enable_events(tc_module, &events);

	/* Set the timer top value to alter the overflow frequency */
	tc_set_top_value(tc_module,
			system_gclk_gen_get_hz(GCLK_GENERATOR_0) / sample_rate);


	tc_enable(tc_module);
}

/**
 * \brief Configures the event system to link the sample timer to the DAC.
 *
 * Configures the event system, linking the TC module used for the audio sample
 * rate timing to the DAC, so that a new conversion is triggered each time the
 * DAC receives an event from the timer.
 */
static void configure_events(void)
{
	events_init();


	struct events_user_config events_user_config;
	events_user_get_config_defaults(&events_user_config);

	events_user_config.event_channel_id = EVENT_CHANNEL_0;

	events_user_set_config(EVSYS_ID_USER_DAC_START, &events_user_config);


	struct events_chan_config events_chan_config;
	events_chan_get_config_defaults(&events_chan_config);

	events_chan_config.generator_id = EVSYS_ID_GEN_TC0_OVF;
	events_chan_config.path         = EVENT_PATH_ASYNCHRONOUS;

	events_chan_set_config(EVENT_CHANNEL_0, &events_chan_config);
}

/**
 * \brief Main application routine
 */
int main(void)
{
	struct dac_module dac_module;
	struct tc_module tc_module;

	/* Initialize all the system clocks, pm, gclk... */
	system_init();

	/* Enable the internal bandgap to use as reference to the DAC */
	system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP);

	/* Module configuration */
	configure_tc(&tc_module);
	configure_dac(&dac_module);
	configure_events();

	/* Start the sample trigger timer */
	tc_start_counter(&tc_module);

	while (true) {
		while (port_pin_get_input_level(SW0_PIN) == SW0_INACTIVE) {
			/* Wait for the button to be pressed */
		}

		port_pin_toggle_output_level(LED0_PIN);

		for (uint32_t i = 0; i < number_of_samples; i++) {
			dac_chan_write(&dac_module, DAC_CHANNEL_0, wav_samples[i]);

			while (!(DAC->INTFLAG.reg & DAC_INTFLAG_EMPTY)) {
				/* Wait for data buffer to be empty */
			}

		}

		while (port_pin_get_input_level(SW0_PIN) == SW0_ACTIVE) {
			/* Wait for the button to be depressed */
		}
	}
}
