#include "KT0915.h"

#define enablePort GPIOB

int deviceAddress = KT0915_I2C_ADDRESS;
int enablePin = GPIO_PIN_0;
uint16_t currentStep;                                   //Stores the current step
uint32_t currentFrequency;                              //Stores the current frequency
uint32_t minimumFrequency;                              //Stores the minimum frequency for the current band
uint32_t maximumFrequency;                              //Stores the maximum frequency for the current band
uint8_t currentMode;                                    //Stores the current mode
uint8_t currentRefClockType = OSCILLATOR_32KHZ;         //Stores the crystal type
uint8_t currentRefClockEnabled = REF_CLOCK_DISABLE;     //Strores 0 = Crystal; 1 = Reference clock
uint8_t currentDialMode = DIAL_MODE_OFF;                //Stores the default Dial Mode (OFF)
uint16_t deviceId;
uint8_t currentVolume = 15;

uint8_t KT0915_getCurrentMode() { return currentMode; };

/* //Set I2C Address

void KT0915_setI2CBusAddress(int N_deviceAddress)
{
    deviceAddress = N_deviceAddress;
} */

void KT0915_setRegister(int reg, uint16_t parameter)
{

    word16_to_bytes param;

    param.raw = parameter;
    //SW_I2C_WriteControl_16Bit(uint8_t sel, uint8_t IICID, uint8_t regaddr, uint16_t data);
    SW_I2C_WriteControl_16Bit(SW_I2C1,deviceAddress,reg,param.raw); //USE SOFT I2C
    HAL_Delay(6);
}

uint16_t KT0915_getRegister(int reg)
{

    word16_to_bytes result;

	//SW_I2C_ReadControl_8Bit(uint8_t sel, uint8_t IICID, uint8_t regaddr)
    result.refined = SW_I2C_ReadControl_16Bit(SW_I2C1,deviceAddress,reg);
    HAL_Delay(6);

    return result.raw;
}

uint16_t KT0915_getDeviceId()
{
    deviceId = KT0915_getRegister(REG_CHIP_ID);
    return deviceId;
}

uint8_t KT0915_isCrystalReady()
{
    kt09xx_statusa reg;
    reg.raw = KT0915_getRegister(REG_STATUSA);
    return reg.refined.XTAL_OK;
}

uint8_t KT0915_PLLStatus()
{
    kt09xx_statusa reg;
    reg.raw = KT0915_getRegister(REG_STATUSA);
    return reg.refined.PLL_LOCK;
}

uint8_t KT0915_LOStatus()
{
    kt09xx_statusa reg;
    reg.raw = KT0915_getRegister(REG_STATUSA);
    return reg.refined.LO_LOCK;
}

/*
 *  * Crystal type table
 * | Dec | binary | Description | defined constant    |
 * | --  | ------ | ----------- | ---------------     |
 * | 0   | 0000   | 32.768KHz   | OSCILLATOR_32KHZ    |
 * | 1   | 0001   | 6.5MHz      | OSCILLATOR_6_5MHZ   |
 * | 2   | 0010   | 7.6MHz      | OSCILLATOR_7_6MHZ   |
 * | 3   | 0011   | 12MHz       | OSCILLATOR_12MHZ    |
 * | 4   | 0100   | 13MHz       | OSCILLATOR_13MHZ    |
 * | 5   | 0101   | 15.2MHz     | OSCILLATOR_15_2MHZ  |
 * | 6   | 0110   | 19.2MHz     | OSCILLATOR_19_2MHZ  | 
 * | 7   | 0111   | 24MHz       | OSCILLATOR_24MHZ    |
 * | 8   | 1000   | 26MHz       | OSCILLATOR_26MHZ    |
 * | 9   | 1001   | ?? 38KHz ?? | OSCILLATOR_38KHz    |
 * 
 */

void KT0915_setReferenceClockType(uint8_t crystal, uint8_t ref_clock)
{
    kt09xx_amsyscfg reg;
    reg.raw = KT0915_getRegister(REG_AMSYSCFG); // Gets the current value of the register
    reg.refined.REFCLK = crystal;        // Changes just crystal parameter
    reg.refined.RCLK_EN = ref_clock;     // Reference Clock Enable => Crystal
    KT0915_setRegister(REG_AMSYSCFG, reg.raw);  // Strores the new value to the register

    currentRefClockType = crystal;
    currentRefClockEnabled = ref_clock;
}


void KT0915_enable(uint8_t on_off)
{
    if (on_off == 0) {
        return;
    } else {
    //HAL_GPIO_WritePin(GPIOx,GPIO_Pin,GPIO_PIN_SET);
    HAL_GPIO_WritePin(enablePort,enablePin,GPIO_PIN_SET);
    TIMER__Wait_us(10);
    }
}

/**
 * @ingroup GA03
 * @todo You need to check mechanical Tune features
 * @brief Sets Tune Dial Mode Interface On  
 * @details This method sets the KT0915 to deal with a mechanical tuning via an external 100K resistor.
 * @details KT0915 supports a unique Dial Mode (mechanical tuning wheel with a variable resistor) which is 
 * @details enabled by GPIO1 to 2 (10). The dial can be a variable resistor with the tap connected to CH (pin 1).  
 * 
 * @see KT0915; Monolithic Digital FM/MW/SW/LW Receiver Radio on a Chip(TM); pages 19 and 20.
 * 
 * @param minimu_frequency   Start frequency for the user band
 * @param maximum_frequency  Final frequency for the user band   
 */
void KT0915_setTuneDialModeOn(uint32_t minimu_frequency, uint32_t maximum_frequency)
{
    kt09xx_amsyscfg reg;
    kt09xx_gpiocfg gpio;
    kt09xx_userstartch uf;
    kt09xx_userguard ug;
    kt09xx_userchannum uc;

    reg.raw = KT0915_getRegister(REG_AMSYSCFG); // Gets the current value from the register
    reg.refined.USERBAND = currentDialMode = DIAL_MODE_ON;
    KT0915_setRegister(REG_AMSYSCFG, reg.raw); // Strores the new value in the register

    gpio.raw = KT0915_getRegister(REG_GPIOCFG); // Gets the current value from the register
    gpio.refined.GPIO1 = 2;              // Sets Dial Mode interface (pin 1/CH)
    KT0915_setRegister(REG_GPIOCFG, gpio.raw);  // Stores the new value in the register
    
    // TODO: Sets the frequency limits for user and

    if (currentMode == MODE_AM)
    {
        uf.refined.USER_START_CHAN = minimu_frequency;
        uc.refined.USER_CHAN_NUM = (maximum_frequency - minimu_frequency) / currentStep;
        ug.refined.USER_GUARD = 0x0011;
    }
    else
    {
        uf.refined.USER_START_CHAN = minimu_frequency / 50;
        uc.refined.USER_CHAN_NUM = ((maximum_frequency - minimu_frequency) / 50) / currentStep;
        ug.refined.USER_GUARD = 0x001D;
    }

    KT0915_setRegister(REG_USERSTARTCH, uf.raw);
    KT0915_setRegister(REG_USERGUARD, ug.raw);
    KT0915_setRegister(REG_USERCHANNUM, uc.raw);
};

/**
 * @ingroup GA03
 * @brief Turns the Tune Dial Mode interface Off
 * @see setTuneDialModeOn
 * @see KT0915; Monolithic Digital FM/MW/SW/LW Receiver Radio on a Chip(TM); page 20.
 */
void KT0915_setTuneDialModeOff()
{
    kt09xx_amsyscfg reg;
    kt09xx_gpiocfg gpio;
    reg.raw = KT0915_getRegister(REG_AMSYSCFG); // Gets the current value of the register
    reg.refined.USERBAND = currentDialMode = DIAL_MODE_OFF;
    KT0915_setRegister(REG_AMSYSCFG, reg.raw); // Strores the new value to the register

    gpio.raw = KT0915_getRegister(REG_GPIOCFG); // Gets the current value of the register
    gpio.refined.GPIO1 = 0;              // Sets MCU (Arduino) control (High Z)
    KT0915_setRegister(REG_GPIOCFG, gpio.raw);  // Stores the new value in the register
}

/**
 * @ingroup GA03
 * @brief   Sets Volume Dial Mode Interface On 
 * @details This method sets the KT0915 to deal with a mechanical volume control via an external 100K resistor.
 * @details KT0915 supports a unique Dial Mode  which is enabled by GPIO2 to 2 (10). 
 * @details The dial can be a variable resistor with the tap connected to VOL (pin 16). 
 * 
 * @see KT0915; Monolithic Digital FM/MW/SW/LW Receiver Radio on a Chip(TM); page 20.
 */
void KT0915_setVolumeDialModeOn()
{
    kt09xx_gpiocfg gpio;
    gpio.raw = KT0915_getRegister(REG_GPIOCFG); // Gets the current value from the register
    gpio.refined.GPIO2 = 2;              // Sets Dial Mode interface (pin 16/VOL)
    KT0915_setRegister(REG_GPIOCFG, gpio.raw);  // Stores the new value in the register
};

/**
 * @ingroup GA03
 * @brief Turns the Volume Dial Mode interface Off
 * @see setVolumeDialModeOn
 * @see KT0915; Monolithic Digital FM/MW/SW/LW Receiver Radio on a Chip(TM); page 20.
 */
void KT0915_setVolumeDialModeOff()
{
    kt09xx_gpiocfg gpio;
    gpio.raw = KT0915_getRegister(REG_GPIOCFG); // Gets the current value of the register
    gpio.refined.GPIO2 = 0;              // Sets to MCU (Arduino) control (High Z)
    KT0915_setRegister(REG_GPIOCFG, gpio.raw);  // Stores the new value in the register
}

/**
 * @ingroup GA03
 * @brief Audio Gain 
 * @details This function set the audio gain you want to use. See table below.
 * | value | Gain Selection |
 * | ----- | -------------- | 
 * |   0   |      3dB       |
 * |   1   |      6dB       |
 * |   2   |     -3dB       | 
 * |   3   |      0dB       |         
 * 
 * @param gain  See table above
 */
void KT0915_setAudioGain(uint8_t gain)
{
    kt09xx_amsyscfg r;
    r.raw = KT0915_getRegister(REG_AMSYSCFG);
    r.refined.AU_GAIN = gain;
    KT0915_setRegister(REG_AMSYSCFG, r.raw);
}

/**
 * @ingroup GA03
 * @brief Sets the audio volume level
 * @details This method is used to control the audio volume level. The value 0 mutes the  device and 31 sets the device to the maximum volume.
 * @param volume between 0 and 31. 
 */
void KT0915_setVolume(uint8_t volume)
{
    kt09xx_rxcfg rx;

    rx.raw = KT0915_getRegister(REG_RXCFG);
    rx.refined.VOLUME = volume;
    KT0915_setRegister(REG_RXCFG, rx.raw);
    currentVolume = volume;
}

/**
 * @ingroup GA03
 * @brief Increases the audio volume
 * 
 */
void KT0915_setVolumeUp()
{
    if (currentVolume == 31)
        return;
    KT0915_setVolume(currentVolume + 1);
}

/**
 * @ingroup GA03
 * @brief Decreases the audio volume
 * 
 */
void KT0915_setVolumeDown()
{
    if (currentVolume == 0)
        return;
    KT0915_setVolume(currentVolume - 1);
}

/**
 * @ingroup GA03
 * @brief Returns the current audio volume 
 * @details Returns a value between 0 and 31.
 * @return uint8_t Value between 0 and 31.
 */
uint8_t KT0915_getVolume()
{
    return currentVolume;
}

void KT0915_SetStandby(uint8_t on_off)
{
    kt09xx_rxcfg rx;

    rx.raw = KT0915_getRegister(REG_RXCFG);
    rx.refined.STDBY = on_off;
    KT0915_setRegister(REG_RXCFG, rx.raw);
}

/**
 * @ingroup GA03
 * @brief AM and FM Softmute control
 * @details The internal KT0915 device register, FM and AM SMUTE 0 means enable and 1 disable. This function inverts this concept. So 1 means enable and 0 disable.
 *  
 * @param on_off 1 = ON (enable); 0 = OFF disable
 */
void KT0915_setSoftMute(uint8_t on_off)
{
    kt09xx_volume v;
    v.raw = KT0915_getRegister(REG_VOLUME);
    v.refined.AMDSMUTE = v.refined.FMDSMUTE  = !on_off;
    KT0915_setRegister(REG_VOLUME, v.raw); // Stores the new values of the register
}

/**
 * @ingroup GA03
 * @brief Sets the bass level
 * @details  Bass Boost Effect Mode Selection
 * | Value | Level   |
 * | ----- | ------- |
 * |   0   | Disable |
 * |   1   | Low     |
 * |   2   | Med     |
 * |   3   | High    | 
 *  
 * @param on_off  see table above
 */
void KT0915_setAudioBass(uint8_t bass)
{
    kt09xx_volume v;
    v.raw = KT0915_getRegister(REG_VOLUME);
    v.refined.BASS = bass;
    KT0915_setRegister(REG_VOLUME, v.raw); // Stores the new values of the register
}

/**
 * @brief  Sets the output audio mute
 * 
 * @param mute_on_off 1 = mute; 0 unmute
 */
void KT0915_setAudioMute(uint8_t mute_on_off)
{
    kt09xx_volume v;

    v.raw = KT0915_getRegister(REG_VOLUME);
    v.refined.DMUTE = !mute_on_off;
    KT0915_setRegister(REG_VOLUME, v.raw); // Stores the new values of the register
}

/**
 * @ingroup GA03
 * @brief Sets Audio DAC Anti-pop Configuration
 * 
 * @details  Bass Boost Effect Mode Selection
 * | Value | AC - coupling capacitor   |
 * | ----- | ------------------------- |
 * |   0   | 100uF   |
 * |   1   | 60uF    |
 * |   2   | 20uF    |
 * |   3   | 10uF    | 
 *  
 * @param on_off  see table above
 */
void KT091_setAudioAntiPop(uint8_t value)
{
    kt09xx_volume v;
    v.refined.POP = value;
    KT0915_setRegister(REG_VOLUME, v.raw); // Stores the new values of the register
}

/**
 * @ingroup GA03
 * @brief Sets the Left Channel Inverse Control 
 * @details If enable, inverts the left channel audio signal
 * @details A fully differential audio signal can be got from LOUT an ROUT if the INV_LEFT_AUDIO bit and MONO bit are set to 1.
 * @param value  ENABLE_ON (1); ENABLE_OFF (0)
 */
void KT0915_setLeftChannelInverseControl(uint8_t enable_disable)
{
    kt09xx_amdsp r;
    r.raw = KT0915_getRegister(REG_AMDSP);
    r.refined.INV_LEFT_AUDIO = enable_disable;
    KT0915_setRegister(REG_AMDSP,r.raw);
}

/**
 * @ingroup GA03
 * @brief   Receiver startup 
 * @details You have to use this method to configure the way that the device will work. For example: enable and disable device control; oscillator type and reference clock type (crystal or external) 
 * @details The tabe below shows  the oscillator frequencies supported by the device.
 * @details If you omit the crystal type parameter, will be considered  0 (32.768KHz). 
 * @details For a low frequency crystal oscillator, selects 32.768KHz or 38KHz crystals. 
 * @details Alternatively, you can use a CMOS level external reference clock may be used by setting 
 * @details the parameter ref_clock to 1 (REF_CLOCK_ENABLE) and setting the reference clock according to the table below.
 * @details The code below shows how to use the setup function.
 * @details the enable_pin parameter sets the way you are controlling the KT0915 pin 9. 
 * 
 * @code
 * #include <KT0915.h>
 * #define RESET_PIN 12   // set it to -1 if you want to use the RST pin of your MCU.
 * KT0915 radio;
 * void setup() {
 *    // Set the parameter enablePin to -1 if you are controlling the enable status via circuit; Select OSCILLATOR_32KHZ, OSCILLATOR_12MHZ etc
 *    // radio.setup(RESET_PIN); Instead the line below, if you use this line, the crystal type considered will be 32.768KHz.   
 *    radio.setup(RESET_PIN, OSCILLATOR_12MHZ, REF_CLOCK_DISABLE );
 * }
 * @endcode
 * 
 * Oscillator frequencies supported
 * | Dec | binary | Description | defined constant    |
 * | --  | ------ | ----------- | ---------------     |
 * | 0   | 0000   | 32.768KHz   | OSCILLATOR_32KHZ    |
 * | 1   | 0001   | 6.5MHz      | OSCILLATOR_6_5MHZ   |
 * | 2   | 0010   | 7.6MHz      | OSCILLATOR_7_6MHZ   |
 * | 3   | 0011   | 12MHz       | OSCILLATOR_12MHZ    |
 * | 4   | 0100   | 13MHz       | OSCILLATOR_13MHZ    |
 * | 5   | 0101   | 15.2MHz     | OSCILLATOR_15_2MHZ  |
 * | 6   | 0110   | 19.2MHz     | OSCILLATOR_19_2MHZ  | 
 * | 7   | 0111   | 24MHz       | OSCILLATOR_24MHZ    |
 * | 8   | 1000   | 26MHz       | OSCILLATOR_26MHZ    |
 * | 9   | 1001   | 38KHz       | OSCILLATOR_38KHz    |
 * 
 * @see KT0915; Monolithic Digital FM/MW/SW/LW Receiver Radio on a Chip(TM); 3.6 Crystal and reference clock; page 9. 
 * @see setReferenceClockType 
 * 
 * @param enablePin         if >= 0,  then you control the device enable or disable status. if -1, you are using the circuit to crontole that. 
 * @param oscillator_type   oscillator type. You can use crystal or external clock. See comments and table above.
 * @param ref_clock         set to 0 if you are using crystal (Reference clock disabled - default); set to 1 if you are using an external reference clock.
 */
void KT0915_setup(uint8_t oscillator_type, uint8_t ref_clock)
{
    KT0915_enable(1);
    HAL_Delay(5);
    KT0915_setReferenceClockType(oscillator_type, ref_clock);
    KT0915_setVolume(currentVolume);
}

/** 
 * @defgroup GA04 Tune Methods 
 * @section  GA04 Tune Methods  
 * @details  Methods to tune and set the receiver mode
 */


/**
 * @ingroup GA04
 * @brief Sets the receiver Stereo or Mono
 * @details Set this parameter to true to force mono or false to stereo
 * @param on_off true = mono; fale = stereo
 */
void KT0915_setMono(uint8_t on_off)
{
    kt09xx_dspcfga reg;
    reg.raw = KT0915_getRegister(REG_DSPCFGA);
    reg.refined.MONO = on_off;
    KT0915_setRegister(REG_DSPCFGA, reg.raw);
}

/**
 * @ingroup GA04
 * @brief Return true if the stereo indicator is set to 3;
 * @return true is stereo
 */
uint8_t KT0915_isFmStereo()
{
    kt09xx_statusa r;
    r.raw = KT0915_getRegister(REG_STATUSA);
    return (r.refined.ST == 3);
}

/**
 * @ingroup GA04
 * @brief Gets the current FM RSSI 
 * 
 * @return int RSSI value
 */
int KT0915_getFmRssi()
{
    kt09xx_statusa r;
    r.raw = KT0915_getRegister(REG_STATUSA);
    return (r.refined.FMRSSI * 3);
};

/**
 * @ingroup GA04
 * @brief Gets the current AM RSSI  
 * 
 * @return int RSSI value
 */
int KT0915_getAmRssi()
{
    kt09xx_amdstatusa r;
    r.raw = KT0915_getRegister(REG_AMSTATUSA);
    return (r.refined.AMRSSI * 3);
};

/**
 * @ingroup GA04
 * @brief Gets current SNR value
 * 
 * @return int  FM SNR value
 */
int KT0915_getFmSnr()
{
    kt09xx_statusc r;
    r.raw = KT0915_getRegister(REG_STATUSC);
    return (r.refined.FMSNR);
};


/**
 * @ingroup GA04
 * @brief Sets the De-emphasis Time Constant Selection
 * @param value 0 = 75us; 1 = 50us 
 */
void KT0915_setDeEmphasis(uint8_t value)
{
    kt09xx_dspcfga reg;
    reg.raw = KT0915_getRegister(REG_DSPCFGA);
    reg.refined.DE = value;
    KT0915_setRegister(REG_DSPCFGA, reg.raw);
}

/**
 * @ingroup GA04
 * @brief Sets FM AFC Disable Control 
 * @details This function inverts the register enable/disable concept. So, here, 1 means enable and 0 disable.
 * @param  on_off  1 = enable AFC; 0 = disable AFC.
 */
void KT0915_setFmAfc(uint8_t on_off)
{
    kt09xx_locfga r;
    r.refined.FMAFCD = !on_off;
    KT0915_setRegister(REG_LOCFGA, r.raw);
}

/**
 * @ingroup GA04
 * @brief Sets AM AFC Disable Control 
 * @details This function inverts the register enable/disable concept. So, here, 1 means enable and 0 disable.
 * @param  on_off  1 = enable AFC; 0 = disable AFC.
 */
void KT0915_setAmAfc(uint8_t on_off)
{
    kt09xx_amsyscfg r;
    r.raw = KT0915_getRegister(REG_AMSYSCFG); // Gets the current value of the register
    r.refined.RESERVED1 = 1;
    r.refined.AMAFCD = !on_off;
    KT0915_setRegister(REG_AMSYSCFG, r.raw);
}

/**
 * @ingroup GA04
 * @brief Sets the AM Space 
 * @details Selects AM channel space 
 * 
 * | value | space |
 * | ----- | ----- | 
 * |   0   |  1KHz | 
 * |   1   |  9KHz |
 * |   2   | 10KHz |
 * |   3   | 10KHz |
 * 
 * @param value  See table above
 */
void KT0915_setAmSpace(uint8_t value)
{
    kt09xx_amcfg r; 
    r.raw = KT0915_getRegister(REG_AMCFG);
    r.refined.AMSPACE = value;
    KT0915_setRegister(REG_AMCFG, r.raw);
}

/**
 * @ingroup GA04
 * @brief Sets AM Channel Bandwidth Selection
 * @details Configures the AM Bandwidth 
 * 
 * | value | Bandwidth |
 * | ----- | --------- | 
 * |   0   |  2KHz     | 
 * |   1   |  2KHz     |
 * |   2   |  4KHz     |
 * |   3   |  6KHz     |
 * 
 * @param value  See table above
 */
void KT0915_setAmBandwidth(uint8_t value)
{
    kt09xx_amdsp r;
    r.raw = KT0915_getRegister(REG_AMDSP);
    r.refined.AM_BW = value;
    KT0915_setRegister(REG_AMDSP, r.raw);
}

/**
 * @ingroup GA04
 * @brief Gets current AM Channel Bandwidth Selection
 * 
 * | value | Bandwidth |
 * | ----- | --------- | 
 * |   0   |  2KHz     | 
 * |   1   |  2KHz     |
 * |   2   |  4KHz     |
 * |   3   |  6KHz     |
 * 
 * @return See table above
 */
uint8_t KT0915_getAmBandwidth()
{
    kt09xx_amdsp r;
    r.raw = KT0915_getRegister(REG_AMDSP);
    return r.refined.AM_BW;
}



/**
 * @todo Adjust setTuneDialOn()
 * @ingroup GA04
 * @brief Sets the receiver to FM mode
 * @details Configures the receiver on FM mode; Also sets the band limits, defaul frequency and step.
 * 
 * @param minimum_frequency  minimum frequency for the band
 * @param maximum_frequency  maximum frequency for the band
 * @param default_frequency  default freuency
 * @param step  increment and decrement frequency step
 */
void KT0915_setFM(uint32_t minimum_frequency, uint32_t maximum_frequency, uint32_t default_frequency, uint16_t step)
{
    kt09xx_amsyscfg reg;

    currentStep = step;
    currentFrequency = default_frequency;
    minimumFrequency = minimum_frequency;
    maximumFrequency = maximum_frequency;
    currentMode = MODE_FM;

    reg.raw = KT0915_getRegister(REG_AMSYSCFG);
    reg.refined.AM_FM = MODE_FM;
    reg.refined.USERBAND = currentDialMode;
    reg.refined.REFCLK = currentRefClockType;
    reg.refined.RCLK_EN = currentRefClockEnabled;
    KT0915_setRegister(REG_AMSYSCFG, reg.raw); // Stores the new value in the register

    if (currentDialMode == DIAL_MODE_ON)
        KT0915_setTuneDialModeOn(minimum_frequency, maximum_frequency);
    else
        KT0915_setFrequency(default_frequency);
};

/**
 * @todo Adjust setTuneDialOn()
 * @ingroup GA04
 * @brief Sets the receiver to AM mode
 * @details Configures the receiver on AM mode; Also sets the band limits, defaul frequency and step.
 * 
 * @param minimum_frequency  minimum frequency for the band
 * @param maximum_frequency  maximum frequency for the band
 * @param default_frequency  default freuency
 * @param step  increment and decrement frequency step
 */
void KT0915_setAM(uint32_t minimum_frequency, uint32_t maximum_frequency, uint32_t default_frequency, uint16_t step, uint8_t am_space)
{
    kt09xx_amsyscfg reg;

    currentStep = step;
    currentFrequency = default_frequency;
    minimumFrequency = minimum_frequency;
    maximumFrequency = maximum_frequency;
    currentMode = MODE_AM;

    reg.raw = KT0915_getRegister(REG_AMSYSCFG);
    reg.refined.AM_FM = MODE_AM;
    reg.refined.USERBAND = currentDialMode;
    reg.refined.REFCLK = currentRefClockType;
    reg.refined.RCLK_EN = currentRefClockEnabled;
    KT0915_setRegister(REG_AMSYSCFG, reg.raw); // Stores the new value in the register
    KT0915_setAmSpace(am_space);

    if (currentDialMode == DIAL_MODE_ON)
        KT0915_setTuneDialModeOn(minimum_frequency, maximum_frequency);
    else
        KT0915_setFrequency(default_frequency);
}

/**
 * @ingroup GA04
 * @brief Sets the current frequency
 * 
 * @param frequency 
 */
void KT0915_setFrequency(uint32_t frequency)
{
    kt09xx_amchan reg_amchan;
    kt09xx_tune reg_tune;

    if (currentMode == MODE_AM)
    {
        reg_amchan.refined.AMTUNE = 1; // TODO Check
        reg_amchan.refined.AMCHAN = frequency;
        KT0915_setRegister(REG_AMCHAN, reg_amchan.raw);
    }
    else
    {
        reg_tune.refined.FMTUNE = 1; // // TODO Check
        reg_tune.refined.RESERVED = 0;
        reg_tune.refined.FMCHAN = frequency / 50;
        KT0915_setRegister(REG_TUNE, reg_tune.raw);
    }

    currentFrequency = frequency;

    TIMER__Wait_us(30);
}

/**
 * @ingroup GA04
 * @brief Increments the frequency one step
 * @details if the frequency plus the step value is greater than the maximum frequency for the band, 
 * @details tne current frequency will be set to minimum frequency.
 * 
 * @see setFrequency
 */
void KT0915_frequencyUp()
{
    currentFrequency += currentStep;
    if (currentFrequency > maximumFrequency)
        currentFrequency = minimumFrequency;

    KT0915_setFrequency(currentFrequency);
}

/**
 * @ingroup GA04
 * @brief Decrements the frequency one step
 * @details if the frequency minus the step value is less than the minimum frequency for the band, 
 * @details tne current frequency will be set to minimum frequency.
 * 
 * @see setFrequency
 */
void KT0915_frequencyDown()
{
    currentFrequency -= currentStep;
    if (currentFrequency < minimumFrequency)
        currentFrequency = maximumFrequency;

    KT0915_setFrequency(currentFrequency);
};

/**
 * @ingroup GA04
 * @brief Sets the frequency step
 * @details Sets increment and decrement frequency 
 * @param step  Values: 1, 5, 9, 10, 100, 200  in KHz
 */
void KT0915_setStep(uint16_t step)
{
    currentStep = step;
}

/**
 * @ingroup GA04
 * @brief Gets the current frequency 
 * @return frequency in KHz
 */
uint32_t KT0915_getFrequency()
{
    return currentFrequency;
}

/**
 * @ingroup GA04
 * @brief Gets the FM Channel Setting 
 * @details This method returns the current channel value for FM tune. 
 * @details The channel value multiplied by 50 is the current FM frequency in KHz.  
 * @return  FM Channel number 
 */
uint16_t KT0915_getFmCurrentChannel() {
    kt09xx_tune r;
    r.raw = KT0915_getRegister(REG_TUNE);
    return r.refined.FMCHAN;
};

/**
 * @ingroup GA04
 * @brief Gets the current AM Channel Setting
 * @details This method returns the current channel value for AM tune
 * @details Actually this value is the AM current frequency in KHz
 * @return  AM Channel number (frequency in KHz) 
 */
uint16_t KT0915_getAmCurrentChannel() {
    kt09xx_amchan r;
    r.raw = KT0915_getRegister(REG_AMCHAN);
    return r.refined.AMCHAN;
};


/**
 * @todo Not enough information to do this so far. 
 * @ingroup GA04
 * @brief Should Seek a station
 * @details However, there no enough information to implement it.
 */
void KT0915_seekStation()
{
    // TODO
}




