#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "bsp.h"
#include "tx_api.h"
#include "airoha_pwr_cal.h"
extern int wln_get_chan_info(int chan_index, int *chan_freq);

#define CALIBRATION_CHANNEL_BG   6
#define CALIBRATION_CHANNEL_BG_MHZ    2437
#define CALIBRATION_CHANNEL_A1   18  //real A188  !!!!!these two numbers have to match!!!!!!
#define CALIBRATION_CHANNEL_A2   26  //real A38   !!!!!these two numbers have to match!!!!!!
#define CALIBRATION_CHANNEL_A3   33  //real A56   !!!!!these two numbers have to match!!!!!!
#define CALIBRATION_CHANNEL_A4   41  //real A120  !!!!!these two numbers have to match!!!!!!
#define CALIBRATION_CHANNEL_A5   49  //real A157  !!!!!these two numbers have to match!!!!!!


static void readLine(char * buf);
int _wifi_AirohaCalib(int index, int maxIndex, int minIndex,
                      float Value1, float Level1,
                      float Value2, float Level2, int lineOrCurve);
static int power_adjust(int calset, float pwr_cal);
extern void SetChannel (int channel);
extern void MacRadioTXRandomBuffer( unsigned int transmit_rate, unsigned int tx_frame_length);
extern void MacContinuousTransmit (int enable, unsigned int transmit_mode, unsigned int transmit_rate);
extern void MacSetDirectTxPower(int value);
static WiFiPwrCal   _wcal[WLN_POWER_CALIBRATION_LENGTH/4];
extern uint32 CalcCRC32 (uint8 *buf, int length);

typedef struct {
        int aChannel;
        int real_aChannel;
        int real_aChannel_frequence;
} T_aChannels;

static T_aChannels cal_a_channels[5] ={{CALIBRATION_CHANNEL_A1, 0, 0},
                                {CALIBRATION_CHANNEL_A2, 0, 0},
                                {CALIBRATION_CHANNEL_A3, 0, 0},
                                {CALIBRATION_CHANNEL_A4, 0, 0},
                                {CALIBRATION_CHANNEL_A5, 0, 0}};

static WiFiPwrCal tempData[WLN_POWER_CALIBRATION_LENGTH/4];
extern BOOLEAN isRF_AIROHA_7230(void);
extern void setAttenuation( unsigned char value);



#define LINEAR_LINE                 0
#define QUADRATIC_CURVE             1

void airoha_calibration (void)
{
    int i, k;
    float pwr1, pwr2, cable_loss = 0.0;
    float adc1, adc2, adc3, adc4;

    int calset1, calset2, calset1_delta=0, calset2_delta=0;
    char buffer[256];
        
    float lowPoint, highPoint,lowPointBG_OFDM, highPointBG_OFDM;
    BOOLEAN isAL7230 = isRF_AIROHA_7230();
        
    if (isAL7230)
    {
        lowPoint = LOW_POINT_AL7230_BG_CCK;
        highPoint = HIGH_POINT_AL7230_BG_CCK;
        lowPointBG_OFDM = LOW_POINT_AL7230_BG_OFDM;
        highPointBG_OFDM = HIGH_POINT_AL7230_BG_OFDM;
    }
    else
    {
        lowPoint = LOW_POINT_AL2236_CCK;
        highPoint = HIGH_POINT_AL2236_CCK;
        lowPointBG_OFDM = LOW_POINT_AL2236_OFDM;
        highPointBG_OFDM = HIGH_POINT_AL2236_OFDM;
    }    
        //set the version number for this calibration
        _wcal[CAL_VERSION].slope = CALIBRATION_VERSION_3;
        
        //and make sure the attenuation is set right: OFDM is -4.86dBm off CCK power
        setAttenuation(0xE0);    
           
    printf("\r\n=====================================================================\r\n");
    printf("== Starting Airoha-specific Radio TX Power calibration procedure...==\r\n");
    printf("==                  On Channel %d (%d MHz)                      ==\r\n",CALIBRATION_CHANNEL_BG, CALIBRATION_CHANNEL_BG_MHZ);
    printf("=====================================================================\r\n");

    /* get RF cable loss */
    printf("Enter RF cable loss (dbm, default is 0.0dbm) >> ");
    readLine(buffer);
        
    /* store the cable loss */
    cable_loss = atof(buffer);
    if (cable_loss < 0.0)
    {
        printf("RF Cable loss is a negative number\r\n");    
        cable_loss = 0;
    }

    printf("RF Cable loss is set to = %5.2f dbm\r\n", cable_loss);    

    SetChannel(CALIBRATION_CHANNEL_BG);
    MacSetDirectTxPower(0);    
    MacContinuousTransmit (1, 0, 0);
    SetChannel(CALIBRATION_CHANNEL_BG);

    printf("...................................................................\r\n");
    
    /* set and adjust TX Pwr setting value */
    calset1 = 34;
    calset1 = power_adjust(calset1, lowPoint - cable_loss);
    calset1_delta = calset1 - 34;
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset1 << 4));   
    tx_thread_sleep(1000);

    printf("Enter the instrument-measured output power level (dBm) >> ");         
    readLine(buffer);
    // RF power level from meter
    pwr1 = atof(buffer);
      
    printf(".....................................................................\r\n");
    printf("Measuring ADC-reported voltage level for a TX Pwr setting of %d...\r\n", calset1);
            
    /* Take 100 ADC readings while transmitting @ 1Mbps on channel 6 */
    adc1 = 0;
    for(i=0; i<100; i++) 
    {
        tx_thread_sleep(10);
        _wapc.Rawdata = _wifi_readadc();
        adc1 += _wapc.Rawdata;            
    }

    adc1 = adc1/100.0;
    printf("1Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset1, (int)adc1, adc1*ADC_RESOLUTION_LSB);            

    MacSetDirectTxPower(0);    
    MacContinuousTransmit (0, 0, 0);
    tx_thread_sleep(10);

    /* set channel */    
    SetChannel(CALIBRATION_CHANNEL_BG);         
    MacContinuousTransmit (1, 0, 11); //enable cont_tx, random data, 54Mbps
    SetChannel(CALIBRATION_CHANNEL_BG);
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset1 << 4)); 
    tx_thread_sleep(1000);

    /* Take 100 ADC readings while transmitting @ 54Mbps on channel 6 same configured TX Pwr setting */
    adc3 = 0;
    for(i=0; i<100; i++) 
    {
        tx_thread_sleep(10);
        _wapc.Rawdata = _wifi_readadc();
        adc3 += _wapc.Rawdata;
    }
    adc3 = adc3/100.0;
    printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset1, (int)adc3, adc3*ADC_RESOLUTION_LSB);

    printf("The difference in ADC-measured voltage levels is: %8.3f mVDC\r\n", (adc1-adc3)*ADC_RESOLUTION_LSB);

    MacSetDirectTxPower(0);
    MacContinuousTransmit (0, 0, 11);

    printf(".....................................................................\r\n");

    tx_thread_sleep(10); 

    /* Obtain the second calibration point at ~17dBm (Max power level for psk/cck) */

    /* set channel */
    SetChannel(CALIBRATION_CHANNEL_BG);     
    MacContinuousTransmit (1, 0, 0); //enable cont_tx, random data, 1Mbps
    SetChannel(CALIBRATION_CHANNEL_BG);

    /* set and adjust TX Pwr setting value */
    calset2 = calset1_delta + 46;
    calset2 = power_adjust(calset2, highPoint - cable_loss);
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset2 << 4)); 
     tx_thread_sleep(1000);
    printf(".....................................................................\r\n");
        
    printf("Enter the instrument-measured Power Level (dBm) >>  ");       
    readLine(buffer);

    // RF power level from meter
    pwr2 = atof(buffer);

    printf(".....................................................................\r\n");

    printf("Measuring ADC-reported voltage level for a TX Pwr setting of %d...\r\n", calset2);

    /* Take 100 ADC readings while transmitting @ 1Mbps on channel 6 */
    adc2 = 0;
    for(i=0; i<100; i++) 
    {
        tx_thread_sleep(10);
        _wapc.Rawdata = _wifi_readadc();
        adc2 += _wapc.Rawdata;
        //printf("\r\n 1Mbps-specific ADC-measured voltage level was: %8.3f mVDC. (ADC code = %d)", _wapc.Rawdata*ADC_RESOLUTION_LSB, _wapc.Rawdata);
    }
    adc2 = adc2/100.0;
    printf("1Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset2, (int)adc2, adc2*ADC_RESOLUTION_LSB);

    MacSetDirectTxPower(0);    
    MacContinuousTransmit (0, 0, 0);  //stop it
    tx_thread_sleep(10);

    /* set channel */
    SetChannel(CALIBRATION_CHANNEL_BG);  
    MacContinuousTransmit (1, 0, 11);  //enable cont_tx, random data, 54Mbps
    SetChannel(CALIBRATION_CHANNEL_BG);
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset2 << 4)); 
    tx_thread_sleep(1000);

    // Read ADC for OFDM power level
    adc4 = 0;
    for(i=0; i<100; i++) 
    {
        tx_thread_sleep(10);
        _wapc.Rawdata = _wifi_readadc();
        adc4 += _wapc.Rawdata;
    }
    adc4 = adc4/100.0;
    printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset2, (int)adc4, adc4*ADC_RESOLUTION_LSB);

    printf("The difference in ADC-measured voltage levels is: %8.3f mVDC\r\n", (adc2-adc4)*ADC_RESOLUTION_LSB);

    MacSetDirectTxPower(0);    
    MacContinuousTransmit (0, 0, 11);

    printf(".....................................................................\r\n");

    // Calibration for calculation of power level based on ADC reading
    printf("CCK modulation-specific calibration results:\r\n");
    printf("_wifi_AirohaCalib(0, calset2, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss)\r\n");
    if (isAL7230)
    { 
        _wifi_AirohaCalib(CAL_BG_BAND_CCK_ONLY, calset2, calset1, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss, QUADRATIC_CURVE);

        printf("CalIndex=%d constantA=%.6f constantB=%.6f maxIndex=%d crc=%lu\r\n",
        CAL_BG_BAND_CCK_ONLY,
        _wcal[0].slope,
        _wcal[0].intercept,
        (int) _wcal[0].maxIndex,
        _wcal[0].crc);
    }
    else
    { 
        _wifi_AirohaCalib(CAL_BG_BAND_CCK_ONLY, calset2, calset1, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss, LINEAR_LINE);

        printf("CalIndex=%d slope=%.6f intercept=%.6f maxIndex=%d crc=%lu\r\n",
        CAL_BG_BAND_CCK_ONLY,
        _wcal[0].slope,
        _wcal[0].intercept,
        (int) _wcal[0].maxIndex,
        _wcal[0].crc);
    }

    printf(".....................................................................\r\n");

    // Calibration for power difference between PSK_CCK vs. OFDM, creates ADC
    // value offset to pad OFDM ADC readings.
    _wifi_AirohaCalib(CAL_BG_BAND_CCK_OFDM_DIFF, calset2, calset1, calset1, adc1-adc3, calset2, adc2-adc4, LINEAR_LINE);

    printf("CCK - OFDM diff calibration results:\r\n");
    printf("_wifi_AirohaCalib(%d, calset2, calset1, adc1-adc3, calset2, adc2-adc4)\r\n", CAL_BG_BAND_CCK_OFDM_DIFF);
    
    printf("CalIndex=%d slope=%.8f intercept=%.8f maxIndex=%d crc=%lu\r\n",
    CAL_BG_BAND_CCK_OFDM_DIFF,
    _wcal[1].slope,
    _wcal[1].intercept,
    (int) _wcal[1].maxIndex,
    _wcal[1].crc);
   
   // next let's calibrate at 54 mbps
    SetChannel(CALIBRATION_CHANNEL_BG);
    MacSetDirectTxPower(0);    
    MacContinuousTransmit (1, 0, 11);
    SetChannel(CALIBRATION_CHANNEL_BG);

    printf("...................................................................\r\n");
    
    /* set and adjust TX Pwr setting value */
    calset1 = 34;
    calset1 = power_adjust(calset1, lowPointBG_OFDM - cable_loss); //!!!!!!!!!!!!!!!!
    calset1_delta = calset1 - 34;
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset1 << 4));   
    tx_thread_sleep(1000);

    printf("Enter the instrument-measured output power level (dBm) >> ");         
    readLine(buffer);
    // RF power level from meter
    pwr1 = atof(buffer);
      
    printf(".....................................................................\r\n");
    printf("Measuring ADC-reported voltage level for a TX Pwr setting of %d...\r\n", calset1);
            
    /* Take 100 ADC readings while transmitting @ 1Mbps on channel 6 */
    adc1 = 0;
    for(i=0; i<100; i++) 
    {
        tx_thread_sleep(10);
        _wapc.Rawdata = _wifi_readadc();
        adc1 += _wapc.Rawdata;            
    }

    adc1 = adc1/100.0;
    printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset1, (int)adc1, adc1*ADC_RESOLUTION_LSB);            

    MacSetDirectTxPower(0);    
    MacContinuousTransmit (0, 0, 11); //stop it
    tx_thread_sleep(10);

    printf(".....................................................................\r\n");

    tx_thread_sleep(10); 

    /* Obtain the second calibration point at ~12dBm (Max power level for OFDM) */

    /* set channel */
    SetChannel(CALIBRATION_CHANNEL_BG);     
    MacContinuousTransmit (1, 0, 11); //enable cont_tx, random data, 54Mbps
    SetChannel(CALIBRATION_CHANNEL_BG);

    /* set and adjust TX Pwr setting value */
    calset2 = calset1_delta + 46;
    calset2 = power_adjust(calset2, highPointBG_OFDM - cable_loss); //!!!!!!!!!!!!!!!!!!!
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset2 << 4)); 
     tx_thread_sleep(1000);
    printf(".....................................................................\r\n");
        
    printf("Enter the instrument-measured Power Level (dBm) >>  ");       
    readLine(buffer);

    // RF power level from meter
    pwr2 = atof(buffer);

    printf(".....................................................................\r\n");

    printf("Measuring ADC-reported voltage level for a TX Pwr setting of %d...\r\n", calset2);

    /* Take 100 ADC readings while transmitting @ 1Mbps on channel 6 */
    adc2 = 0;
    for(i=0; i<100; i++) 
    {
        tx_thread_sleep(10);
        _wapc.Rawdata = _wifi_readadc();
        adc2 += _wapc.Rawdata;
        //printf("\r\n 1Mbps-specific ADC-measured voltage level was: %8.3f mVDC. (ADC code = %d)", _wapc.Rawdata*ADC_RESOLUTION_LSB, _wapc.Rawdata);
    }
    adc2 = adc2/100.0;
    printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset2, (int)adc2, adc2*ADC_RESOLUTION_LSB);

    MacSetDirectTxPower(0);    
    MacContinuousTransmit (0, 0, 11);  //stop it
    tx_thread_sleep(10);
    

    printf(".....................................................................\r\n");

    // Calibration for calculation of power level based on ADC reading
    printf("OFDM modulation-specific calibration results:\r\n");
    printf("_wifi_AirohaCalib(%d, calset2, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss)\r\n", CAL_BG_BAND_OFDM_ONLY);
    if (isAL7230)
    { 
        _wifi_AirohaCalib(CAL_BG_BAND_OFDM_ONLY, calset2, calset1, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss, QUADRATIC_CURVE);

        printf("CalIndex=%d constantA=%.6f constantB=%.6f maxIndex=%d crc=%lu\r\n",
        CAL_BG_BAND_OFDM_ONLY,
        _wcal[CAL_BG_BAND_OFDM_ONLY].slope,
        _wcal[CAL_BG_BAND_OFDM_ONLY].intercept,
        (int) _wcal[CAL_BG_BAND_OFDM_ONLY].maxIndex,
        _wcal[CAL_BG_BAND_OFDM_ONLY].crc);
    }
    else
    { 
        _wifi_AirohaCalib(CAL_BG_BAND_OFDM_ONLY, calset2, calset1, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss, LINEAR_LINE);

        printf("CalIndex=%d slope=%.6f intercept=%.6f maxIndex=%d crc=%lu\r\n",
        CAL_BG_BAND_OFDM_ONLY,
        _wcal[CAL_BG_BAND_OFDM_ONLY].slope,
        _wcal[CAL_BG_BAND_OFDM_ONLY].intercept,
        (int) _wcal[CAL_BG_BAND_OFDM_ONLY].maxIndex,
        _wcal[CAL_BG_BAND_OFDM_ONLY].crc);
    }

    
    printf("...................................................................\r\n\r\n");
    
    // if this board has a band support, we need to calibrate 5 more ponits on each sub_a_band
    calset1_delta=0;
    calset2_delta=0;
    if (isAL7230)
    {
        lowPoint = LOW_POINT_AL7230_A;
        highPoint = HIGH_POINT_AL7230_A;                                               
            
        printf("== This board supports A band channels, Calibrate on A channels...  ==\r\n");
        for (k=0; k<5; k++)
        {
            cal_a_channels[k].real_aChannel = wln_get_chan_info(cal_a_channels[k].aChannel, &cal_a_channels[k].real_aChannel_frequence);
            printf("==                  On Channel A%d (%d MHz)                        ==\r\n",cal_a_channels[k].real_aChannel, cal_a_channels[k].real_aChannel_frequence);
                    
            /* get RF cable loss */
            printf("Enter RF cable loss (dbm, default is 0.0dbm) >> ");
            readLine(buffer);
            /* store the cable loss */
            cable_loss = atof(buffer);

            if (cable_loss < 0.0)
            {
                printf("RF Cable loss is a negative number\r\n");
                cable_loss = 0;
            }
    
            printf("RF Cable loss is set to = %5.2f dbm\r\n", cable_loss);    
        
            /* set channel */
            SetChannel(cal_a_channels[k].aChannel);         
            MacContinuousTransmit (1, 0, 11);  //enable cont_tx, random data, 54Mbps
            SetChannel(cal_a_channels[k].aChannel);
            
            /* set and adjust TX Pwr setting value */
            calset1 = calset1_delta + 40;
            calset1 = power_adjust(calset1, lowPoint - cable_loss);
            calset1_delta = calset1 - (calset1_delta + 40) ;
            _wifi_Airoha(AIROHA_PWR_SETTING | (calset1 << 4));   
             tx_thread_sleep(1000);
    
            printf("...................................................................\r\n");
     
            printf("Enter the instrument-measured output power level (dbm) >>  ");        
            readLine(buffer);
            // RF power level from meter
            pwr1 = atof(buffer);
                      
            printf(".....................................................................\r\n");
            printf("Measuring ADC-reported voltage level for a TX Pwr setting of %d...\r\n", calset1);
                    
            /* Take 100 ADC readings while transmitting @ 54Mbps on this channel */
            adc1 = 0;
            for(i=0; i<100; i++) 
            {
                tx_thread_sleep(10);
                _wapc.Rawdata = _wifi_readadc();
                adc1 += _wapc.Rawdata;            
            }
    
            adc1 = adc1/100.0;
            printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset1, (int)adc1, adc1*ADC_RESOLUTION_LSB);
    
            MacSetDirectTxPower(0);
            MacContinuousTransmit (0, 0, 11);
            tx_thread_sleep(10);
            
            printf("...................................................................\r\n");
            
            /* set channel */
            SetChannel(cal_a_channels[k].aChannel);         
            MacContinuousTransmit (1, 0, 11);  //enable cont_tx, random data, 54Mbps
            SetChannel(cal_a_channels[k].aChannel);
            
            /* set and adjust TX Pwr setting value */
            calset2 = calset2_delta + 55;
            calset2 = power_adjust(calset2, highPoint - cable_loss);
            calset2_delta = calset2 - (calset2_delta + 55);
            _wifi_Airoha(AIROHA_PWR_SETTING | (calset2 << 4)); 
             tx_thread_sleep(1000);
            printf("...................................................................\r\n");
              
            printf("Enter the instrument-measured Power Level (dbm) >>  ");       
            readLine(buffer);
    
            // RF power level from meter
            pwr2 = atof(buffer);
    
            printf("...................................................................\r\n");
    
            printf("Measuring ADC-reported voltage level for a TX Pwr setting of %d...\r\n", calset2);
            /* Take 100 ADC readings while transmitting @ 54Mbps on this channel */
            adc2 = 0;
            for(i=0; i<100; i++) 
            {
                tx_thread_sleep(10);
                _wapc.Rawdata = _wifi_readadc();
                adc2 += _wapc.Rawdata;            
            }
    
            adc2 = adc2/100.0;
            
            printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg ADC-reported voltage level: %8.3f mVDC\r\n", calset2, (int)adc2, adc2*ADC_RESOLUTION_LSB);
            
            // Calibration for calculation of power level based on ADC reading
            _wifi_AirohaCalib(k+2, calset2, calset1, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss, QUADRATIC_CURVE);
    
            printf("OFDM modulation-specific calibration results:\r\n");
            printf("_wifi_AirohaCalib(%d, calset2, adc1, pwr1+cable_loss, adc2, pwr2+cable_loss)\r\n", (k+2));
            printf("CalIndex=%d constantA=%.6f constantB=%.6f maxIndex=%d crc=%lu\r\n",
            (k+2),
            _wcal[k+2].slope,
            _wcal[k+2].intercept,
            (int) _wcal[k+2].maxIndex,
            _wcal[k+2].crc);
            
            printf(".....................................................................\r\n");
            
            MacSetDirectTxPower(0);    
            MacContinuousTransmit (0, 0, 11);
            tx_thread_sleep(10);
        }
    
    }
        
    printf("\r\nWriting Radio calibration data to flash...");
    fflush(stdout);
    if (setPowerCalibrationData(_wcal))
    {
        printf("error!\r\n");
        return;
    }
    else
        printf("done!\r\n");


    printf("Reading Radio calibration data from flash...");
    fflush(stdout);
    memset (tempData, 0, sizeof tempData);
    if (getPowerCalibrationData(tempData))
    {
        printf("error!\r\n");
        return;
    }
    else
        printf("done!\r\n");

    printf("Verifying Radio calibration data stored in flash...");
    fflush(stdout);
    if(memcmp(_wcal, tempData, sizeof tempData))
    {
        printf("error!\r\n");        
        return;
    }
    else
        printf("done!\r\n");   
    
    __wifi_SetPower (15);
    
    printf("\r\n== !!! Airoha-specific Radio TX Power calibration has completed !! \r\n");
}

/**************************************************************
 * airoha_ADC_complete_characterization()                     * 
 *      Fully characterizes the transmitter portion of        * 
 *      the radio transceiver                                 *
 **************************************************************/
void airoha_complete_characterization (void)
{
    int i,j;
    float adc1, adc3;

    printf("\r\n=====================================================================");
    printf("== Measuring transceiver-reported signal for all TX Pwr settings...==\r\n");
    printf("==                  On Channel %d (%d MHz)                       ==\r\n",CALIBRATION_CHANNEL_BG, CALIBRATION_CHANNEL_BG_MHZ);
    printf("=====================================================================\r\n");

    SetChannel(CALIBRATION_CHANNEL_BG);
    MacSetDirectTxPower(0);
    MacContinuousTransmit (1, 0, 0);
    SetChannel(CALIBRATION_CHANNEL_BG);
    
    /* 1Mbps specific ADC readings */
    for (j=0;j<64;j++)
    {
        MacSetDirectTxPower(j);
        tx_thread_sleep(100);

        // Read ADC for PSK_CCK power level
        adc1 = 0;
        for(i=0; i<100; i++) 
        {
            tx_thread_sleep(2);
            _wapc.Rawdata = _wifi_readadc();
            adc1 += _wapc.Rawdata;            
        }
        adc1 = adc1/100.0;
        printf("1Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d, Avg transceiver-reported output signal = %8.3f mVDC\r\n", j, (int)adc1, adc1*ADC_RESOLUTION_LSB);
        tx_thread_sleep(1000);
    }       

    printf(".....................................................................\r\n");
    
    MacContinuousTransmit (0, 0, 0);        
    tx_thread_sleep(10);

    SetChannel(CALIBRATION_CHANNEL_BG);
    MacSetDirectTxPower(0);    
    MacContinuousTransmit (1, 0, 11);
    SetChannel(CALIBRATION_CHANNEL_BG);

    /* Taking 54Mbps specific ADC readings for all tx power configurable index values */
    for (j=0;j<64;j++)
    {
        MacSetDirectTxPower(j);
        tx_thread_sleep(100);
   
        adc3 = 0;
        for(i=0; i<100; i++) 
        {
            tx_thread_sleep(2);
            _wapc.Rawdata = _wifi_readadc();
            adc3 += _wapc.Rawdata;
        }
        adc3 = adc3/100.0;
        printf("54Mbps - Configured TX Pwr setting: %d, Avg ADC Code: %d,Avg transceiver-reported output signal = %8.3f mVDC\r\n", j, (int)adc3, adc3 *ADC_RESOLUTION_LSB);         
        tx_thread_sleep(1000);
    }
    
    MacContinuousTransmit (0, 0, 11);

    __wifi_SetPower (15);
    
    printf("\r\n=====================================================================\r\n");
    printf("== Airoha-specific Radio TX Pwr characterization was completed...  ==\r\n");
    printf("=====================================================================\r\n");
}

/**************************************************************
 * airoha_ADC_digital_Reading_versus_Analog_Reading()         * 
 * Note: It requires a voltmeter connected to the analog      *
 *       input (Vin) of the ADC convertor.                    *
 **************************************************************/
void airoha_ADC_Digital_Reading_versus_Analog_Reading (void)
{
    int i;
    unsigned int pwr_index_value = 0;
    
    /* Voltmeter measured analog signal. Voltmeter connect to Vin pin */
    float input_analog_signal = 0.0;
        
    /*Average ADC code for a given TX PWR setting value */
    float average_adc_code = 0.0;
    
    char buffer[256];
    
    printf("\r\n=====================================================================/r/n");
    printf("== Measuring Airoha-reported signal for a specific TX Pwr setting. ==/r/n");
    printf("==                  On Channel %d (%d MHz)                       ==/r/n",CALIBRATION_CHANNEL_BG, CALIBRATION_CHANNEL_BG_MHZ);
    printf("=====================================================================/r/n");    
    
    /* get index value */
    printf("Enter a TX Pwr index value(0-63) >> ");
    readLine(buffer);
    
    /* store the cable loss */
    pwr_index_value = atoi(buffer);
                      
    SetChannel(CALIBRATION_CHANNEL_BG);
    MacSetDirectTxPower(0);
    MacContinuousTransmit (1, 0, 0);  //enable cont_tx, random data, 1Mbps
    SetChannel(CALIBRATION_CHANNEL_BG);
    
    printf(".....................................................................\r\n");
    
    MacSetDirectTxPower(pwr_index_value);
    tx_thread_sleep(100);
    
    /* Prompt user for the value of analog signal measured by the voltmeter */
    printf("Enter the signal value reported by the voltmeter(mVDC) >> ");         
    readLine(buffer);
    input_analog_signal = atof(buffer);  
    printf("Voltmeter-measured input analog signal is: %8.3f mVDC\r\n", input_analog_signal);   
    
    printf(".................................................................\r\n");
    printf("Sampling input analog signal 10 times (please wait)...\r\n");       
    
    tx_thread_sleep(100);
    average_adc_code = 0;                
    // Read ADC for PSK_CCK power level
    for(i=0; i<10; i++) 
    {
        tx_thread_sleep(2);
        _wapc.Rawdata = _wifi_readadc();
        average_adc_code += _wapc.Rawdata;                
        printf("1Mbps - Configured TX Pwr setting: %d, Voltmeter-measured input analog value = %8.3f mVDC\r\n ADC Code: %d, transceiver-reported output signal = %8.3f mVDC\r\n Difference = %8.3f mVDC\r\n", pwr_index_value, input_analog_signal, _wapc.Rawdata, _wapc.Rawdata*ADC_RESOLUTION_LSB, _wapc.Rawdata*ADC_RESOLUTION_LSB - input_analog_signal);
    }
    
    printf(".....................................................................\r\n");
                  
    average_adc_code = average_adc_code/10.0;
    
    printf("1Mbps - Configured TX Pwr setting: %d, Voltmeter-measured input analog value = %8.3f mVDC\r\n Avg ADC Code: %d,Avg transceiver-reported output signal = %8.3f mVDC\r\n", pwr_index_value, input_analog_signal, (int)average_adc_code, average_adc_code*ADC_RESOLUTION_LSB);                
    tx_thread_sleep(100);
    
    printf(".....................................................................\r\n");
        
    MacContinuousTransmit (0, 0, 0); 
    MacSetDirectTxPower(0);         
    tx_thread_sleep(100);    
    
    SetChannel(CALIBRATION_CHANNEL_BG);
    MacSetDirectTxPower(0);
    MacContinuousTransmit (1, 0, 11);  //enable cont_tx, random data, 54Mbps
    SetChannel(CALIBRATION_CHANNEL_BG);
    
    printf("...................................................................\r\n");
    
    MacSetDirectTxPower(pwr_index_value);
    tx_thread_sleep(100);
    
    /* Prompt user for the value of analog signal measured by the voltmeter */
    printf("Enter the signal value reported by the voltmeter(mVDC) >> ");         
   
    readLine(buffer);
    input_analog_signal = atof(buffer);  
    printf("Voltmeter-measured input analog signal is: %8.3f mVDC\r\n", input_analog_signal);
    
    printf(".................................................................\r\n");
    printf("Sampling input analog signal 10 times (please wait)...\r\n");       
    
    tx_thread_sleep(100);
    
    average_adc_code=0;                
    // Read ADC for OFDM power level
    for(i=0; i<10; i++) 
    {
        tx_thread_sleep(2);
        _wapc.Rawdata = _wifi_readadc();
        average_adc_code += _wapc.Rawdata;                
        printf("54Mbps - Configured TX Pwr setting: %d, Voltmeter-measured input analog value = %8.3f mVDC\r\n ADC Code: %d, transceiver-reported output signal = %8.3f mVDC\r\n Difference = %8.3f mVDC\r\n", 
                pwr_index_value, input_analog_signal, _wapc.Rawdata, _wapc.Rawdata*ADC_RESOLUTION_LSB, _wapc.Rawdata*ADC_RESOLUTION_LSB - input_analog_signal);    
    }
    
    printf(".....................................................................\r\n");
                  
    average_adc_code = average_adc_code/10.0;
    
    printf("54Mbps - Configured TX Pwr setting: %d, Voltmeter-measured input analog value = %8.3f mVDC\r\n Avg ADC Code: %d, Avg transceiver-reported output signal = %8.3f mVDC\r\n", 
            pwr_index_value, input_analog_signal, (int)average_adc_code, average_adc_code*ADC_RESOLUTION_LSB);
    tx_thread_sleep(100);
    
    printf(".....................................................................\r\n");
        
    MacContinuousTransmit (0, 0, 11); 
    MacSetDirectTxPower(0);         
    tx_thread_sleep(100);    
}

static void readLine(char * buf)
{
    char character;
    int i = 0;

    fflush(stdout);

    do
    {
        character = getchar();
        if (character == '\b') 
        {
           if (i > 0)
           {
              putchar(character);
              putchar(0x20);   /*space*/
              putchar(character);
              --i;
           }
        }

        else if (character != '\n')
        {
           buf[i] = character;
           putchar(character);
           ++i;
        }
        fflush(stdout);
    }while (character != '\r');

    putchar('\n');
    if (i > 0)
        buf[i-1] = '\0';
}  


int _wifi_AirohaCalib(int idx, int maxIndex, int minIndex,
                      float Value1, float Level1,
                      float Value2, float Level2, int lineOrCurve)
{
    float constantA,constantB;
    float slope, intercept;  
    long crc = 0;
    int extension_idx;

    if(Value1 == Value2 || Level1 == Level2)
        return -1;

    if (lineOrCurve == QUADRATIC_CURVE)
    {
         /* 
          * Since the response of the AL7230 detector is not very linear, we could do a simple quadratic curve fit 
          * to provide a wider range of closed loop power control.  If we express the result in power (not log(P)), 
          * we know the Y-intercept is 0.  So the equation is Y = Ax^2 + Bx.  This only requires two points to 
          * determine the variables A and B -
          *
          * A = (P1/V1 - P0/V0)/(V1 - V0)
          * B = P1/V1 - A*V1
          *
          * P1 = Power (mW) for the upper calibration point
          * V1 = Detector voltage (or ADC value) for the upper calibration point 
          * P1 = Power (mW) for the lower calibration point
          * V1 = Detector voltage (or ADC value) for the lower calibration point
          * 
          * See the enclosed spreadsheet.  For this example I chose the calibration points as 17.8 dBm and 6.85 dBm for 2.4 Ghz, and 14.1 dBm and 5.4 dBm for 5 Ghz.
          * 
          * The manufacturing calibration routine can compute the values A and B and store these as the calibration 
          * data for a given band.  This is similar to the current algorithm except we are using a 2nd order equation 
          * instead of a 1st order.  To eliminate the need to perform log(x) at runtime, we can just create a table 
          * which converts the desired target power in dBm to milliwatts.  This is probably not more than about 20 entries.
          *
          */
          //let's convert the dbm to mW first: mW = 10 ^(dBm/10)
          Level1 = pow(10, (Level1/10));
          Level2 = pow(10, (Level2/10));
          
          constantA = (Level2/Value2 - Level1/Value1)/(Value2 - Value1);
          constantB = Level2/Value2 - constantA * Value2;
          
          _wcal[idx].slope   = constantA;
          _wcal[idx].intercept = constantB;
          _wcal[idx].maxIndex = (long)((maxIndex & 0x0000ffff) | ((minIndex & 0x0000ffff) << 16));                         
            
    }
    else
    {
        /* LINEAR_LINE */
        slope   = (Value2 - Value1) / (Level2 - Level1);
        intercept =  Level2 - (Value2/slope);

        _wcal[idx].slope   = slope;
        _wcal[idx].intercept = intercept;
        _wcal[idx].maxIndex = (long)((maxIndex & 0x0000ffff) | ((minIndex & 0x0000ffff) << 16));   
    }
    
    crc = CalcCRC32 ((uint8 *)&_wcal[idx],
                 sizeof(_wcal[idx]) -  sizeof(long));
    _wcal[idx].crc = crc;

    if (idx != CAL_BG_BAND_OFDM_ONLY)
    {
        extension_idx = idx+8;
    }
    else
    {
        extension_idx = CAL_BG_BAND_OFDM_ONLY_EXT;
    }
    
    if (idx != CAL_BG_BAND_CCK_OFDM_DIFF)
    {
        _wcal[extension_idx].slope = Level1;
        _wcal[extension_idx].intercept = Level2;
        _wcal[extension_idx].maxIndex = (long)(((int)Value2 & 0x000000ff) | (((int)Value1 & 0x000000ff) << 16));   
        crc = CalcCRC32 ((uint8 *)&_wcal[extension_idx],
                     sizeof(_wcal[extension_idx]) -  sizeof(long));
        _wcal[extension_idx].crc = crc;
    }
        
   return 0;
}

// Function to allow operator to manually set the Airoha power level to
// calibration target power level.   
static int power_adjust(int calset, float pwr_cal)
{
    int option;
    int done;
    
    printf("\r\nAdjust configured TX Pwr level by pressing '+' or '-' until the measured output power is appx %.2f dBm. Press 'X' when done >>\r\n", pwr_cal);
    if(calset > 63)
        calset = 63;
            
    _wifi_Airoha(AIROHA_PWR_SETTING | (calset << 4));
    done = FALSE;
    while(!done)
    {
        option = getchar();

        switch(option)
        {
            case '+':
                calset++;
                if(calset > 63)
                    calset = 63;
    
                _wifi_Airoha(AIROHA_PWR_SETTING | (calset << 4));
                tx_thread_sleep(200);
                printf("Configured Power Index value = %d \r", calset);
                fflush(stdout);
                break;
    
            case '-':
                calset--;
                if(calset < 0)
                    calset = 0;
                _wifi_Airoha(AIROHA_PWR_SETTING | (calset << 4));
                tx_thread_sleep(200);
                printf("Configured Power Index value = %d \r", calset);
                fflush(stdout);
                break;
    
            case 'X':
            case 'x':
                printf("\n");               
                done = TRUE;
                break;
          }
    }
    
    return calset;
}
