/*
 * Copyright 2019-2020 NXP
 * This software is owned or controlled by NXP and may only be used strictly
 * in accordance with the applicable license terms.  By expressly accepting
 * such terms or by downloading, installing, activating and/or otherwise using
 * the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms.  If you do not agree to
 * be bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software.
 */

/**
 * @defgroup KL_MODULES_AUDIOSERVICE_TX_API TX API
 * @ingroup KL_MODULES_AUDIOSERVICE
 * @anchor audio_transmitter
 *
 * The audio TX (transmitter) service is responsible for sending audio data over I2S.
 *
 * For this, it initializes the I2S and DMA interfaces using the KL ports and registers.
 * Audio packets are written to a ring buffer and then transferred from the KL to the I2S block over DMA.
 *
 * Check the @ref KL_MODULES_AUDIOSERVICE_TX_SEQ_DIG "sequence diagram" for more info.
 *
 * @{
 */

#ifndef AUDIO_TX_H_
#define AUDIO_TX_H_

/* ---------------------------------------------------------------------------- */
/* Include files                                                                */
/* ---------------------------------------------------------------------------- */

#include <stdint.h>
#include "audio.h"

/* ---------------------------------------------------------------------------- */
/* Defines                                                                      */
/* ---------------------------------------------------------------------------- */

/**
 * Callback type used by the Audio Transmitter to get new samples to be transmitted.
 *
 * @param[out] pDest Pointer to the (memory) destination address, where the requested samples have to be written to.
 * @param[in]  nbSamples Number of audio samples to be written.
 */
typedef void (*audio_get_samples_cb)(void *pDest, uint16_t nbSamples);

/* -------------------------------------------------------------------------
 * Public functions
 * ------------------------------------------------------------------------- */

/**
 * Initialization of Transmitter part of audio
 *  Configures I2S, Inits I2S, Inits Audio Formats, Inits SAI,
 *  Inits DMA
 */
void audio_InitTx(void);

/**
 * Start sending audio samples to I2S
 *  Starts DMA, Starts SAI, Enables I2S interrupts
 *
 * @param getEmptySamplesCb The transmitter will call this function initially to transfer empty samples.
 * @param getMixedSamplesCb The transmitter will repeatedly call this function to transfer mixed samples.
 */
void audio_StartTx(audio_get_samples_cb getEmptySamplesCb, audio_get_samples_cb getMixedSamplesCb);

/**
 * Stops the data transmission.
 */
void audio_StopTx(void);

/**
 * Resets the transmitter
 */
void audio_ResetTx(void);

/**
 * Get the number of bytes left in the current transfer.
 *
 * @return the number of bytes left in the current transfer.
 */
uint32_t audio_GetBytesLeftInTransfer(void);

/** @} */

/**
 * @{
 *
 * @defgroup KL_MODULES_AUDIOSERVICE_TX_SEQ_DIG TX sequence diagrams
 * @ingroup KL_MODULES_AUDIOSERVICE
 * @par Sequence diagram of Audio TX Service
 *
 *  <dl><dt>Initialization and configuration</dt><dd>
 *      @msc
 *      msc=omegapple;
 *      hscale=auto;
 *      text.wrap=no;
 *      TX [label="Audio TX"];
 *      RB [label="Audio RingBuffer"];
 *      DMA [label="DMA Interface"];
 *      SAI [label="SAI"];
 *      |||;
 *      ---: I2S pins initialized;
 *      ->TX: Initialize TX [url="@ref audio_InitTx"];
 *      TX->SAI: Initialize TX SAI;
 *      TX->SAI: Enable TX I2S;
 *      TX->DMA: Configure TX DMA;
 *      <<TX;
 *      @endmsc
 *
 *  </dd><dt>Starting the transmitter</dt><dd>
 *  In the diagram below, note how the number of audio samples requested by the transmitter changes. That is:
 *  - First, the transmitter gets the equivalent of **2 DMA transfers**.
 *  - Afterwards, from within the DMA TX CallBack, the transmitter always gets the equivalent of **1 DMA transfer**.
 *  .
 *  The reasoning behind this, is the following. The DMA TX CallBack is executed every time 1 DMA transfer has completed.
 *  So, at that moment we simply have to ask for the equivalent amount of samples, to keep the shared buffer at a consistent
 *  filling level. The size of the ring buffer must be at least 2 times the DMA transfer size: while a certain block is
 *  being transferred by the DMA component, the transmitter has to already prepare (fill) the next block of data (to avoid
 *  transferring a block to which we're still writing). So, when we get the very first DMA TX CallBack, the second DMA block
 *  already had to be filled as well. Therefore, the transmitter initially gets the equivalent of 2 DMA transfers.
 *      @msc
 *      msc=omegapple;
 *      hscale=auto;
 *      text.wrap=no;
 *      TX [label="Audio TX"];
 *      RB [label="Audio RingBuffer"];
 *      DMA [label="DMA Interface"];
 *      SAI [label="SAI"];
 *      |||;
 *      ---: Transmitter initialized;
 *      ->TX: Start the transmitter [URL = "@ref audio_StartTx"];
 *      <-TX: GetSamplesCb(2 x DMA transfer size);
 *      TX->RB: Write samples to ring buffer;
 *      TX->DMA: Start TX DMA;
 *      TX->SAI: Enable TX I2S interrupts;
 *      <<TX;
 *      mark loop_top;
 *      ...: DMA transfer ongoing;
 *      TX<<DMA: DMA TX CallBack;
 *      <-TX: GetSamplesCb(1 x DMA transfer size);
 *      TX->RB: Write samples to ring buffer;
 *      TX->DMA: Prepare next DMA transfer;
 *      vertical brace loop_top<-> at SAI+ :Repeat\n (streaming);
 *      @endmsc
 *
 *  </dd><dt>Stopping the transmitter</dt><dd>
 *      @msc
 *      msc=omegapple;
 *      hscale=auto;
 *      text.wrap=no;
 *      TX [label="Audio TX"];
 *      RB [label="Audio RingBuffer"];
 *      DMA [label="DMA Interface"];
 *      SAI [label="SAI"];
 *      |||;
 *      ---: Transmitter initialized and started;
 *      ->TX: Stop the transmitter [URL = "@ref audio_StopTx"];
 *      TX->DMA: Stop TX DMA;
 *      TX->DMA: Abort current DMA transfer;
 *      TX->DMA: Reconfigure TX DMA;
 *      TX->SAI: Disable TX I2S interrupts;
 *      TX->RB: Reset ring buffer;
 *      <<TX;
 *      @endmsc
 *
 *  </dd></dl>
 *
 */

/** @} */

#endif /* AUDIO_TX_H_ */
