1805 lines
62 KiB
C
1805 lines
62 KiB
C
// $Id: $
|
|
/****************************************************************************
|
|
*
|
|
* **** I
|
|
* ****** ***
|
|
* ******* ****
|
|
* ******** **** **** **** ********* ******* **** ***********
|
|
* ********* **** **** **** ********* ************** *************
|
|
* **** ***** **** **** **** **** ***** ****** ***** ****
|
|
* **** ***** **** **** **** **** ***** **** **** ****
|
|
* **** ********* **** **** **** **** **** **** ****
|
|
* **** ******** **** ****I **** ***** ***** **** ****
|
|
* **** ****** ***** ****** ***** ****** ******* ****** *******
|
|
* **** **** ************ ****** ************* *************
|
|
* **** *** **** **** **** ***** **** ***** ****
|
|
* ****
|
|
* I N N O V A T I O N T O D A Y F O R T O M M O R O W ****
|
|
* ***
|
|
*
|
|
************************************************************************//**
|
|
*
|
|
* @file eeprom.c
|
|
* @brief SuperFemto EEPROM interface.
|
|
*
|
|
* Author : Yves Godin
|
|
* Date : 2012
|
|
* $Revision: $
|
|
*
|
|
* Copyright (c) Nutaq. 2012
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* "$Revision: $"
|
|
* "$Name: $"
|
|
* "$Date: $"
|
|
*
|
|
***************************************************************************/
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include "eeprom.h"
|
|
|
|
//#define DISP_ERROR 1
|
|
|
|
#ifdef DISP_ERROR
|
|
#define PERROR(x, args ...) fprintf(stderr, x, ## args)
|
|
#else
|
|
#define PERROR(x, args ...) do { } while (0)
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private constants *
|
|
****************************************************************************/
|
|
|
|
/**
|
|
* EEPROM device file
|
|
*/
|
|
#define EEPROM_DEV "/sys/bus/i2c/devices/i2c-1/1-0050/eeprom"
|
|
|
|
/**
|
|
* EEPROM configuration start address
|
|
*/
|
|
#define EEPROM_CFG_START_ADDR 0x0100
|
|
|
|
/**
|
|
* EEPROM configuration max size
|
|
*/
|
|
#define EEPROM_CFG_MAX_SIZE (0x2000 - EEPROM_CFG_START_ADDR)
|
|
|
|
/**
|
|
* EEPROM config magic ID
|
|
*/
|
|
#define EEPROM_CFG_MAGIC_ID 0x53464548
|
|
|
|
/**
|
|
* EEPROM header version
|
|
*/
|
|
#define EEPROM_HDR_V1 1
|
|
#define EEPROM_HDR_V2 2
|
|
|
|
/**
|
|
* EEPROM section ID
|
|
*/
|
|
typedef enum
|
|
{
|
|
EEPROM_SID_SYSINFO = 0x1000, ///< System information
|
|
EEPROM_SID_RFCLOCK_CAL = 0x2000, ///< RF Clock Calibration
|
|
EEPROM_SID_GSM850_TXCAL = 0x3000, ///< GSM-850 TX Calibration Table
|
|
EEPROM_SID_GSM850_RXUCAL = 0x3010, ///< GSM-850 RX Uplink Calibration Table
|
|
EEPROM_SID_GSM850_RXDCAL = 0x3020, ///< GSM-850 RX Downlink Calibration Table
|
|
EEPROM_SID_GSM900_TXCAL = 0x3100, ///< GSM-900 TX Calibration Table
|
|
EEPROM_SID_GSM900_RXUCAL = 0x3110, ///< GSM-900 RX Uplink Calibration Table
|
|
EEPROM_SID_GSM900_RXDCAL = 0x3120, ///< GSM-900 RX Downlink Calibration Table
|
|
EEPROM_SID_DCS1800_TXCAL = 0x3200, ///< DCS-1800 TX Calibration Table
|
|
EEPROM_SID_DCS1800_RXUCAL = 0x3210, ///< DCS-1800 RX Uplink Calibration Table
|
|
EEPROM_SID_DCS1800_RXDCAL = 0x3220, ///< DCS-1800 RX Downlink Calibration Table
|
|
EEPROM_SID_PCS1900_TXCAL = 0x3300, ///< PCS-1900 TX Calibration Table
|
|
EEPROM_SID_PCS1900_RXUCAL = 0x3310, ///< PCS-1900 RX Uplink Calibration Table
|
|
EEPROM_SID_PCS1900_RXDCAL = 0x3320, ///< PCS-1900 RX Downlink Calibration Table
|
|
EEPROM_SID_ASSY = 0x3400 ///< Assembly information
|
|
} eeprom_SID_t;
|
|
|
|
/****************************************************************************
|
|
* Private types *
|
|
****************************************************************************/
|
|
|
|
/**
|
|
* TX calibration table (common part) V1
|
|
*/
|
|
typedef struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
|
|
int16_t sfixTxGainGmsk[80]; ///< [Q10.5] Gain setting for GMSK output level from +50dBm to -29 dBm
|
|
int16_t sfixTx8PskCorr; ///< [Q6.9] Gain adjustment for 8 PSK (default to +3.25 dB)
|
|
int16_t sfixTxExtAttCorr[31]; ///< [Q6.9] Gain adjustment for external attenuator (0:@1dB, 1:@2dB, ..., 31:@32dB)
|
|
int16_t sfixTxRollOffCorr[0]; ///< [Q6.9] Gain correction for each ARFCN
|
|
} __attribute__((packed)) eeprom_CfgTxCal_t;
|
|
|
|
/**
|
|
* RX calibration table (common part) V1
|
|
*/
|
|
typedef struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
|
|
uint16_t u16IqImbalMode; ///< IQ imbalance mode (0:off, 1:on, 2:auto)
|
|
uint16_t u16IqImbalCorr[4]; ///< IQ imbalance compensation
|
|
|
|
int16_t sfixExtRxGain; ///< [Q6.9] External RX gain
|
|
int16_t sfixRxMixGainCorr; ///< [Q6.9] Mixer gain error compensation
|
|
int16_t sfixRxLnaGainCorr[3]; ///< [Q6.9] LNA gain error compensation (1:@-12 dB, 2:@-24 dB, 3:@-36 dB)
|
|
int16_t sfixRxRollOffCorr[0]; ///< [Q6.9] Frequency roll-off compensation
|
|
} __attribute__((packed)) eeprom_CfgRxCal_t;
|
|
|
|
/**
|
|
* TX calibration table (common part) V2
|
|
*/
|
|
typedef struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
uint8_t u8DspMajVer; ///< DSP firmware major version
|
|
uint8_t u8DspMinVer; ///< DSP firmware minor version
|
|
uint8_t u8FpgaMajVer; ///< FPGA firmware major version
|
|
uint8_t u8FpgaMinVer; ///< FPGA firmware minor version
|
|
int16_t sfixTxGainGmsk[80]; ///< [Q10.5] Gain setting for GMSK output level from +50dBm to -29 dBm
|
|
int16_t sfixTx8PskCorr; ///< [Q6.9] Gain adjustment for 8 PSK (default to +3.25 dB)
|
|
int16_t sfixTxExtAttCorr[31]; ///< [Q6.9] Gain adjustment for external attenuator (0:@1dB, 1:@2dB, ..., 31:@32dB)
|
|
int16_t sfixTxRollOffCorr[0]; ///< [Q6.9] Gain correction for each ARFCN
|
|
} __attribute__((packed)) eeprom_CfgTxCalV2_t;
|
|
|
|
/**
|
|
* RX calibration table (common part) V2
|
|
*/
|
|
typedef struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
uint8_t u8DspMajVer; ///< DSP firmware major version
|
|
uint8_t u8DspMinVer ; ///< DSP firmware minor version
|
|
uint8_t u8FpgaMajVer; ///< FPGA firmware major version
|
|
uint8_t u8FpgaMinVer; ///< FPGA firmware minor version
|
|
uint16_t u16IqImbalMode; ///< IQ imbalance mode (0:off, 1:on, 2:auto)
|
|
uint16_t u16IqImbalCorr[4]; ///< IQ imbalance compensation
|
|
int16_t sfixExtRxGain; ///< [Q6.9] External RX gain
|
|
int16_t sfixRxMixGainCorr; ///< [Q6.9] Mixer gain error compensation
|
|
int16_t sfixRxLnaGainCorr[3]; ///< [Q6.9] LNA gain error compensation (1:@-12 dB, 2:@-24 dB, 3:@-36 dB)
|
|
int16_t sfixRxRollOffCorr[0]; ///< [Q6.9] Frequency roll-off compensation
|
|
} __attribute__((packed)) eeprom_CfgRxCalV2_t;
|
|
|
|
|
|
/**
|
|
* EEPROM configuration area format
|
|
*/
|
|
typedef struct
|
|
{
|
|
struct
|
|
{
|
|
uint32_t u32MagicId; ///< Magic ID (0x53464548)
|
|
uint32_t u16Version : 16; ///< Header format version (v1)
|
|
uint32_t : 16; ///< unused
|
|
} hdr;
|
|
|
|
union
|
|
{
|
|
/** EEPROM Format V1 */
|
|
struct
|
|
{
|
|
/** System information */
|
|
struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
|
|
char szSn[16]; ///< Serial number
|
|
uint32_t u8Rev : 8; ///< Board revision
|
|
uint32_t u2Tcxo : 2; ///< TCXO present (0:absent, 1:present, x:unknown)
|
|
uint32_t u2Ocxo : 2; ///< OCXO present (0:absent, 1:present, x:unknown)
|
|
uint32_t u2GSM850 : 2; ///< GSM-850 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t u2GSM900 : 2; ///< GSM-900 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t u2DCS1800 : 2; ///< GSM-1800 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t u2PCS1900 : 2; ///< GSM-1900 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t : 12; ///< unused
|
|
} __attribute__((packed)) sysInfo;
|
|
|
|
/** RF Clock configuration */
|
|
struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
|
|
int i24ClkCor :24; ///< Clock correction value in PPB.
|
|
uint32_t u8ClkSrc : 8; ///< Clock source (0:None, 1:OCXO, 2:TCXO, 3:External, 4:GPS PPS, 5:reserved, 6:RX, 7:Edge)
|
|
} __attribute__((packed)) rfClk;
|
|
|
|
/** GSM-850 TX Calibration Table */
|
|
eeprom_CfgTxCal_t gsm850TxCal;
|
|
uint16_t __gsm850TxCalMem[124];
|
|
|
|
/** GSM-850 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCal_t gsm850RxuCal;
|
|
uint16_t __gsm850RxuCalMem[124];
|
|
|
|
/** GSM-850 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCal_t gsm850RxdCal;
|
|
uint16_t __gsm850RxdCalMem[124];
|
|
|
|
/** GSM-900 TX Calibration Table */
|
|
eeprom_CfgTxCal_t gsm900TxCal;
|
|
uint16_t __gsm900TxCalMem[194];
|
|
|
|
/** GSM-900 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCal_t gsm900RxuCal;
|
|
uint16_t __gsm900RxuCalMem[194];
|
|
|
|
/** GSM-900 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCal_t gsm900RxdCal;
|
|
uint16_t __gsm900RxdCalMem[194];
|
|
|
|
/** DCS-1800 TX Calibration Table */
|
|
eeprom_CfgTxCal_t dcs1800TxCal;
|
|
uint16_t __dcs1800TxCalMem[374];
|
|
|
|
/** DCS-1800 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCal_t dcs1800RxuCal;
|
|
uint16_t __dcs1800RxuCalMem[374];
|
|
|
|
/** DCS-1800 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCal_t dcs1800RxdCal;
|
|
uint16_t __dcs1800RxdCalMem[374];
|
|
|
|
/** PCS-1900 TX Calibration Table */
|
|
eeprom_CfgTxCal_t pcs1900TxCal;
|
|
uint16_t __pcs1900TxCalMem[299];
|
|
|
|
/** PCS-1900 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCal_t pcs1900RxuCal;
|
|
uint16_t __pcs1900RxuCalMem[299];
|
|
|
|
/** PCS-1900 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCal_t pcs1900RxdCal;
|
|
uint16_t __pcs1900RxdCalMem[299];
|
|
|
|
} __attribute__((packed)) v1;
|
|
|
|
/** EEPROM Format V2 */
|
|
struct
|
|
{
|
|
/** System information */
|
|
struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
char szSn[16]; ///< Serial number
|
|
uint32_t u8Rev : 8; ///< Board revision
|
|
uint32_t u2Tcxo : 2; ///< TCXO present (0:absent, 1:present, x:unknown)
|
|
uint32_t u2Ocxo : 2; ///< OCXO present (0:absent, 1:present, x:unknown)
|
|
uint32_t u2GSM850 : 2; ///< GSM-850 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t u2GSM900 : 2; ///< GSM-900 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t u2DCS1800 : 2; ///< GSM-1800 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t u2PCS1900 : 2; ///< GSM-1900 supported (0:unsupported, 1:supported, x:unknown)
|
|
uint32_t : 12; ///< unused
|
|
} __attribute__((packed)) sysInfo;
|
|
|
|
/** RF Clock configuration */
|
|
struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
|
|
int i24ClkCor :24; ///< Clock correction value in PPB.
|
|
uint32_t u8ClkSrc : 8; ///< Clock source (0:None, 1:OCXO, 2:TCXO, 3:External, 4:GPS PPS, 5:reserved, 6:RX, 7:Edge)
|
|
} __attribute__((packed)) rfClk;
|
|
|
|
/** GSM-850 TX Calibration Table */
|
|
eeprom_CfgTxCalV2_t gsm850TxCalV2;
|
|
uint16_t __gsm850TxCalMemV2[124];
|
|
|
|
/** GSM-850 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCalV2_t gsm850RxuCalV2;
|
|
uint16_t __gsm850RxuCalMemV2[124];
|
|
|
|
/** GSM-850 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCalV2_t gsm850RxdCalV2;
|
|
uint16_t __gsm850RxdCalMemV2[124];
|
|
|
|
/** GSM-900 TX Calibration Table */
|
|
eeprom_CfgTxCalV2_t gsm900TxCalV2;
|
|
uint16_t __gsm900TxCalMemV2[194];
|
|
|
|
/** GSM-900 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCalV2_t gsm900RxuCalV2;
|
|
uint16_t __gsm900RxuCalMemV2[194];
|
|
|
|
/** GSM-900 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCalV2_t gsm900RxdCalV2;
|
|
uint16_t __gsm900RxdCalMemV2[194];
|
|
|
|
/** DCS-1800 TX Calibration Table */
|
|
eeprom_CfgTxCalV2_t dcs1800TxCalV2;
|
|
uint16_t __dcs1800TxCalMemV2[374];
|
|
|
|
/** DCS-1800 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCalV2_t dcs1800RxuCalV2;
|
|
uint16_t __dcs1800RxuCalMemV2[374];
|
|
|
|
/** DCS-1800 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCalV2_t dcs1800RxdCalV2;
|
|
uint16_t __dcs1800RxdCalMemV2[374];
|
|
|
|
/** PCS-1900 TX Calibration Table */
|
|
eeprom_CfgTxCalV2_t pcs1900TxCalV2;
|
|
uint16_t __pcs1900TxCalMemV2[299];
|
|
|
|
/** PCS-1900 RX Uplink Calibration Table */
|
|
eeprom_CfgRxCalV2_t pcs1900RxuCalV2;
|
|
uint16_t __pcs1900RxuCalMemV2[299];
|
|
|
|
/** PCS-1900 RX Downlink Calibration Table */
|
|
eeprom_CfgRxCalV2_t pcs1900RxdCalV2;
|
|
uint16_t __pcs1900RxdCalMemV2[299];
|
|
|
|
/** Assembly information */
|
|
struct
|
|
{
|
|
uint16_t u16SectionID; ///< Section ID
|
|
uint16_t u16Crc; ///< Parity
|
|
uint32_t u32Time; ///< Epoch time
|
|
char szSn[16]; ///< System serial number
|
|
char szPartNum[20]; ///< System part number
|
|
uint8_t u8TsID ; ///< Test station ID
|
|
uint8_t u8TstVer ; ///< Test version
|
|
uint8_t u8PaType; ///< PA type (0: None, 1-254 supported, 255 ; Unknown)
|
|
uint8_t u8PaBand; ///< PA GSM band (0: Unknown, 1: 850 MHz, 2: 900 MHz, 4: 1800 MHz, 8: 1900 MHz)
|
|
uint8_t u8PaMajVer; ///< PA major version
|
|
uint8_t u8PaMinVer; ///< PA minor version
|
|
} __attribute__((packed)) assyInfo;
|
|
} __attribute__((packed)) v2;
|
|
} __attribute__((packed)) cfg;
|
|
} __attribute__((packed)) eeprom_Cfg_t;
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
* Private routine prototypes *
|
|
****************************************************************************/
|
|
|
|
static int eeprom_read( int addr, int size, char *pBuff );
|
|
static int eeprom_write( int addr, int size, const char *pBuff );
|
|
static uint16_t eeprom_crc( uint8_t *pu8Data, int len );
|
|
static eeprom_Cfg_t *eeprom_cached_config(void);
|
|
|
|
|
|
/****************************************************************************
|
|
* Public functions *
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_ResetCfg
|
|
************************************************************************//**
|
|
*
|
|
* This function reset the content of the EEPROM config area.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_ResetCfg( void )
|
|
{
|
|
int err;
|
|
eeprom_Cfg_t ee;
|
|
|
|
// Clear the structure
|
|
memset( &ee, 0xFF, sizeof(eeprom_Cfg_t) );
|
|
|
|
// Init the header
|
|
ee.hdr.u32MagicId = EEPROM_CFG_MAGIC_ID;
|
|
ee.hdr.u16Version = EEPROM_HDR_V2;
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR, sizeof(ee.hdr) + sizeof(ee.cfg.v2), (const char *) &ee );
|
|
if ( err != sizeof(ee.hdr) + sizeof(ee.cfg.v2) )
|
|
{
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
eeprom_Error_t eeprom_ReadEthAddr( uint8_t *ethaddr )
|
|
{
|
|
int err;
|
|
|
|
err = eeprom_read(0, 6, (char *) ethaddr);
|
|
if ( err != 6 )
|
|
{
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_ReadSysInfo
|
|
************************************************************************//**
|
|
*
|
|
* This function reads the system information from the EEPROM.
|
|
*
|
|
* @param [inout] pTime
|
|
* Pointer to a system info structure.
|
|
*
|
|
* @param [inout] pSysInfo
|
|
* Pointer to a system info structure.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_ReadSysInfo( eeprom_SysInfo_t *pSysInfo )
|
|
{
|
|
int err;
|
|
eeprom_Cfg_t ee;
|
|
|
|
// Get a copy of the EEPROM header
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(ee.hdr), (char *) &ee.hdr );
|
|
if ( err != sizeof(ee.hdr) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the header magic ID
|
|
if ( ee.hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
PERROR( "Invalid EEPROM format\n" );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
switch ( ee.hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V1:
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
// Get a copy of the EEPROM section
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR + offsetof(eeprom_Cfg_t, cfg.v1.sysInfo), sizeof(ee.cfg.v1.sysInfo), (char *)&ee.cfg.v1.sysInfo );
|
|
if ( err != sizeof(ee.cfg.v1.sysInfo) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the ID
|
|
if ( ee.cfg.v1.sysInfo.u16SectionID != EEPROM_SID_SYSINFO )
|
|
{
|
|
PERROR( "Uninitialized data section\n" );
|
|
return EEPROM_ERR_UNAVAILABLE;
|
|
}
|
|
|
|
// Validate the CRC
|
|
if ( eeprom_crc( (uint8_t *)&ee.cfg.v1.sysInfo.u32Time, sizeof(ee.cfg.v1.sysInfo) - 2 * sizeof(uint16_t) ) != ee.cfg.v1.sysInfo.u16Crc )
|
|
{
|
|
PERROR( "Parity error\n" );
|
|
return EEPROM_ERR_PARITY;
|
|
}
|
|
|
|
// Expand the content of the section
|
|
memcpy( (void *)pSysInfo->szSn, ee.cfg.v1.sysInfo.szSn, sizeof(pSysInfo->szSn) );
|
|
pSysInfo->u8Rev = ee.cfg.v1.sysInfo.u8Rev;
|
|
pSysInfo->u8Tcxo = ee.cfg.v1.sysInfo.u2Tcxo;
|
|
pSysInfo->u8Ocxo = ee.cfg.v1.sysInfo.u2Ocxo;
|
|
pSysInfo->u8GSM850 = ee.cfg.v1.sysInfo.u2GSM850;
|
|
pSysInfo->u8GSM900 = ee.cfg.v1.sysInfo.u2GSM900;
|
|
pSysInfo->u8DCS1800 = ee.cfg.v1.sysInfo.u2DCS1800;
|
|
pSysInfo->u8PCS1900 = ee.cfg.v1.sysInfo.u2PCS1900;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_WriteSysInfo
|
|
************************************************************************//**
|
|
*
|
|
* This function writes the system information to the EEPROM.
|
|
*
|
|
* @param [in] pSysInfo
|
|
* Pointer to the system info structure to be written.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_WriteSysInfo( const eeprom_SysInfo_t *pSysInfo )
|
|
{
|
|
int err;
|
|
eeprom_Cfg_t ee;
|
|
|
|
// Get a copy of the EEPROM header
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(ee.hdr), (char *) &ee.hdr );
|
|
if ( err != sizeof(ee.hdr) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the header magic ID
|
|
if ( ee.hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
// Init the header
|
|
ee.hdr.u32MagicId = EEPROM_CFG_MAGIC_ID;
|
|
ee.hdr.u16Version = EEPROM_HDR_V2;
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR, sizeof(ee.hdr) + sizeof(ee.cfg.v1), (const char *) &ee );
|
|
if ( err != sizeof(ee.hdr) + sizeof(ee.cfg.v1) )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
}
|
|
|
|
switch ( ee.hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
ee.cfg.v1.sysInfo.u16SectionID = EEPROM_SID_SYSINFO;
|
|
ee.cfg.v1.sysInfo.u16Crc = 0;
|
|
ee.cfg.v1.sysInfo.u32Time = time(NULL);
|
|
|
|
// Compress the info
|
|
memcpy( ee.cfg.v1.sysInfo.szSn, pSysInfo->szSn, sizeof(ee.cfg.v1.sysInfo.szSn) );
|
|
ee.cfg.v1.sysInfo.u8Rev = pSysInfo->u8Rev;
|
|
ee.cfg.v1.sysInfo.u2Tcxo = pSysInfo->u8Tcxo;
|
|
ee.cfg.v1.sysInfo.u2Ocxo = pSysInfo->u8Ocxo;
|
|
ee.cfg.v1.sysInfo.u2GSM850 = pSysInfo->u8GSM850;
|
|
ee.cfg.v1.sysInfo.u2GSM900 = pSysInfo->u8GSM900;
|
|
ee.cfg.v1.sysInfo.u2DCS1800 = pSysInfo->u8DCS1800;
|
|
ee.cfg.v1.sysInfo.u2PCS1900 = pSysInfo->u8PCS1900;
|
|
|
|
// Add the CRC
|
|
ee.cfg.v1.sysInfo.u16Crc = eeprom_crc( (uint8_t *)&ee.cfg.v1.sysInfo.u32Time, sizeof(ee.cfg.v1.sysInfo) - 2 * sizeof(uint16_t) );
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR + offsetof(eeprom_Cfg_t, cfg.v1.sysInfo), sizeof(ee.cfg.v1.sysInfo), (const char *) &ee.cfg.v1.sysInfo );
|
|
if ( err != sizeof(ee.cfg.v1.sysInfo) )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_ReadRfClockCal
|
|
************************************************************************//**
|
|
*
|
|
* This function reads the RF clock calibration data from the EEPROM.
|
|
*
|
|
* @param [inout] pRfClockCal
|
|
* Pointer to a RF clock calibration structure.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_ReadRfClockCal( eeprom_RfClockCal_t *pRfClockCal )
|
|
{
|
|
int err;
|
|
eeprom_Cfg_t ee;
|
|
|
|
// Get a copy of the EEPROM header
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(ee), (char *) &ee );
|
|
if ( err != sizeof(ee) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the header magic ID
|
|
if ( ee.hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
PERROR( "Invalid EEPROM format\n" );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
switch ( ee.hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V1:
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
// Get a copy of the EEPROM section
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR + offsetof(eeprom_Cfg_t, cfg.v1.rfClk), sizeof(ee.cfg.v1.rfClk), (char *)&ee.cfg.v1.rfClk );
|
|
if ( err != sizeof(ee.cfg.v1.rfClk) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the ID
|
|
if ( ee.cfg.v1.rfClk.u16SectionID != EEPROM_SID_RFCLOCK_CAL )
|
|
{
|
|
PERROR( "Uninitialized data section\n" );
|
|
return EEPROM_ERR_UNAVAILABLE;
|
|
}
|
|
|
|
// Validate the CRC
|
|
if ( eeprom_crc( (uint8_t *)&ee.cfg.v1.rfClk.u32Time, sizeof(ee.cfg.v1.rfClk) - 2 * sizeof(uint16_t) ) != ee.cfg.v1.rfClk.u16Crc )
|
|
{
|
|
PERROR( "Parity error\n" );
|
|
return EEPROM_ERR_PARITY;
|
|
}
|
|
|
|
// Expand the content of the section
|
|
pRfClockCal->iClkCor = ee.cfg.v1.rfClk.i24ClkCor;
|
|
pRfClockCal->u8ClkSrc = ee.cfg.v1.rfClk.u8ClkSrc;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_WriteRfClockCal
|
|
************************************************************************//**
|
|
*
|
|
* This function writes the RF clock calibration data to the EEPROM.
|
|
*
|
|
* @param [in] pSysInfo
|
|
* Pointer to the system info structure to be written.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_WriteRfClockCal( const eeprom_RfClockCal_t *pRfClockCal )
|
|
{
|
|
int err;
|
|
eeprom_Cfg_t ee;
|
|
|
|
// Get a copy of the EEPROM header
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(ee.hdr), (char *) &ee.hdr );
|
|
if ( err != sizeof(ee.hdr) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the header magic ID
|
|
if ( ee.hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
// Init the header
|
|
ee.hdr.u32MagicId = EEPROM_CFG_MAGIC_ID;
|
|
ee.hdr.u16Version = EEPROM_HDR_V2;
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR, sizeof(ee.hdr) + sizeof(ee.cfg.v1), (const char *) &ee );
|
|
if ( err != sizeof(ee.hdr) + sizeof(ee.cfg.v1) )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
}
|
|
|
|
switch ( ee.hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
ee.cfg.v1.rfClk.u16SectionID = EEPROM_SID_RFCLOCK_CAL;
|
|
ee.cfg.v1.rfClk.u16Crc = 0;
|
|
ee.cfg.v1.rfClk.u32Time = time(NULL);
|
|
|
|
// Compress the info
|
|
ee.cfg.v1.rfClk.i24ClkCor = pRfClockCal->iClkCor;
|
|
ee.cfg.v1.rfClk.u8ClkSrc = pRfClockCal->u8ClkSrc;
|
|
|
|
// Add the CRC
|
|
ee.cfg.v1.rfClk.u16Crc = eeprom_crc( (uint8_t *)&ee.cfg.v1.rfClk.u32Time, sizeof(ee.cfg.v1.rfClk) - 2 * sizeof(uint16_t) );
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR + offsetof(eeprom_Cfg_t, cfg.v1.rfClk), sizeof(ee.cfg.v1.rfClk), (const char *) &ee.cfg.v1.rfClk );
|
|
if ( err != sizeof(ee.cfg.v1.rfClk) )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_ReadTxCal
|
|
************************************************************************//**
|
|
*
|
|
* This function reads the TX calibration tables for the specified band from
|
|
* the EEPROM.
|
|
*
|
|
* @param [in] iBand
|
|
* GSM band (0:GSM-850, 1:GSM-900, 2:DCS-1800, 3:PCS-1900).
|
|
*
|
|
* @param [inout] pTxCal
|
|
* Pointer to a TX calibration table structure.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_ReadTxCal( int iBand, eeprom_TxCal_t *pTxCal )
|
|
{
|
|
int i;
|
|
int size;
|
|
int nArfcn;
|
|
eeprom_Cfg_t *ee = eeprom_cached_config();
|
|
eeprom_SID_t sId;
|
|
eeprom_CfgTxCal_t *pCfgTxCal = NULL;
|
|
eeprom_CfgTxCalV2_t *pCfgTxCalV2 = NULL;
|
|
|
|
// Get a copy of the EEPROM header
|
|
if (!ee)
|
|
{
|
|
PERROR( "Reading cached content failed.\n" );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
switch ( ee->hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V1:
|
|
{
|
|
switch ( iBand )
|
|
{
|
|
case 0:
|
|
nArfcn = 124;
|
|
sId = EEPROM_SID_GSM850_TXCAL;
|
|
pCfgTxCal = &ee->cfg.v1.gsm850TxCal;
|
|
size = sizeof(ee->cfg.v1.gsm850TxCal) + sizeof(ee->cfg.v1.__gsm850TxCalMem);
|
|
break;
|
|
case 1:
|
|
nArfcn = 194;
|
|
sId = EEPROM_SID_GSM900_TXCAL;
|
|
pCfgTxCal = &ee->cfg.v1.gsm900TxCal;
|
|
size = sizeof(ee->cfg.v1.gsm900TxCal) + sizeof(ee->cfg.v1.__gsm900TxCalMem);
|
|
break;
|
|
case 2:
|
|
nArfcn = 374;
|
|
sId = EEPROM_SID_DCS1800_TXCAL;
|
|
pCfgTxCal = &ee->cfg.v1.dcs1800TxCal;
|
|
size = sizeof(ee->cfg.v1.dcs1800TxCal) + sizeof(ee->cfg.v1.__dcs1800TxCalMem);
|
|
break;
|
|
case 3:
|
|
nArfcn = 299;
|
|
sId = EEPROM_SID_PCS1900_TXCAL;
|
|
pCfgTxCal = &ee->cfg.v1.pcs1900TxCal;
|
|
size = sizeof(ee->cfg.v1.pcs1900TxCal) + sizeof(ee->cfg.v1.__pcs1900TxCalMem);
|
|
break;
|
|
default:
|
|
PERROR( "Invalid GSM band specified (%d)\n", iBand );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
// Validate the ID
|
|
if ( pCfgTxCal->u16SectionID != sId )
|
|
{
|
|
PERROR( "Uninitialized data section\n" );
|
|
return EEPROM_ERR_UNAVAILABLE;
|
|
}
|
|
|
|
// Validate the CRC
|
|
if ( eeprom_crc( (uint8_t *)&pCfgTxCal->u32Time, size - 2 * sizeof(uint16_t) ) != pCfgTxCal->u16Crc )
|
|
{
|
|
PERROR( "Parity error\n" );
|
|
return EEPROM_ERR_PARITY;
|
|
}
|
|
|
|
// Expand the content of the section
|
|
for ( i = 0; i < 80; i++ )
|
|
{
|
|
pTxCal->fTxGainGmsk[i] = (float)pCfgTxCal->sfixTxGainGmsk[i] * 0.03125f;
|
|
}
|
|
pTxCal->fTx8PskCorr = (float)pCfgTxCal->sfixTx8PskCorr * 0.001953125f;
|
|
for ( i = 0; i < 31; i++ )
|
|
{
|
|
pTxCal->fTxExtAttCorr[i] = (float)pCfgTxCal->sfixTxExtAttCorr[i] * 0.001953125f;
|
|
}
|
|
for ( i = 0; i < nArfcn; i++ )
|
|
{
|
|
pTxCal->fTxRollOffCorr[i] = (float)pCfgTxCal->sfixTxRollOffCorr[i] * 0.001953125f;
|
|
}
|
|
|
|
//DSP firmware version
|
|
pTxCal->u8DspMajVer = 0;
|
|
pTxCal->u8DspMinVer = 0;
|
|
|
|
//FPGA firmware version
|
|
pTxCal->u8FpgaMajVer = 0;
|
|
pTxCal->u8FpgaMinVer = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
|
|
switch ( iBand )
|
|
{
|
|
case 0:
|
|
nArfcn = 124;
|
|
sId = EEPROM_SID_GSM850_TXCAL;
|
|
pCfgTxCalV2 = &ee->cfg.v2.gsm850TxCalV2;
|
|
size = sizeof(ee->cfg.v2.gsm850TxCalV2) + sizeof(ee->cfg.v2.__gsm850TxCalMemV2);
|
|
break;
|
|
case 1:
|
|
nArfcn = 194;
|
|
sId = EEPROM_SID_GSM900_TXCAL;
|
|
pCfgTxCalV2 = &ee->cfg.v2.gsm900TxCalV2;
|
|
size = sizeof(ee->cfg.v2.gsm900TxCalV2) + sizeof(ee->cfg.v2.__gsm900TxCalMemV2);
|
|
break;
|
|
case 2:
|
|
nArfcn = 374;
|
|
sId = EEPROM_SID_DCS1800_TXCAL;
|
|
pCfgTxCalV2 = &ee->cfg.v2.dcs1800TxCalV2;
|
|
size = sizeof(ee->cfg.v2.dcs1800TxCalV2) + sizeof(ee->cfg.v2.__dcs1800TxCalMemV2);
|
|
break;
|
|
case 3:
|
|
nArfcn = 299;
|
|
sId = EEPROM_SID_PCS1900_TXCAL;
|
|
pCfgTxCalV2 = &ee->cfg.v2.pcs1900TxCalV2;
|
|
size = sizeof(ee->cfg.v2.pcs1900TxCalV2) + sizeof(ee->cfg.v2.__pcs1900TxCalMemV2);
|
|
break;
|
|
default:
|
|
PERROR( "Invalid GSM band specified (%d)\n", iBand );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
|
|
// Validate the ID
|
|
if ( pCfgTxCalV2->u16SectionID != sId )
|
|
{
|
|
PERROR( "Uninitialised data section\n" );
|
|
return EEPROM_ERR_UNAVAILABLE;
|
|
}
|
|
|
|
// Validate the CRC
|
|
if ( eeprom_crc( (uint8_t *)&pCfgTxCalV2->u32Time, size - 2 * sizeof(uint16_t) ) != pCfgTxCalV2->u16Crc )
|
|
{
|
|
PERROR( "Parity error\n" );
|
|
return EEPROM_ERR_PARITY;
|
|
}
|
|
|
|
// Expand the content of the section
|
|
for ( i = 0; i < 80; i++ )
|
|
{
|
|
pTxCal->fTxGainGmsk[i] = (float)pCfgTxCalV2->sfixTxGainGmsk[i] * 0.03125f;
|
|
}
|
|
pTxCal->fTx8PskCorr = (float)pCfgTxCalV2->sfixTx8PskCorr * 0.001953125f;
|
|
for ( i = 0; i < 31; i++ )
|
|
{
|
|
pTxCal->fTxExtAttCorr[i] = (float)pCfgTxCalV2->sfixTxExtAttCorr[i] * 0.001953125f;
|
|
}
|
|
for ( i = 0; i < nArfcn; i++ )
|
|
{
|
|
pTxCal->fTxRollOffCorr[i] = (float)pCfgTxCalV2->sfixTxRollOffCorr[i] * 0.001953125f;
|
|
}
|
|
|
|
//DSP firmware version
|
|
pTxCal->u8DspMajVer = pCfgTxCalV2->u8DspMajVer;
|
|
pTxCal->u8DspMinVer = pCfgTxCalV2->u8DspMinVer;
|
|
|
|
//FPGA firmware version
|
|
pTxCal->u8FpgaMajVer = pCfgTxCalV2->u8FpgaMajVer;
|
|
pTxCal->u8FpgaMinVer = pCfgTxCalV2->u8FpgaMinVer;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_WriteTxCal
|
|
************************************************************************//**
|
|
*
|
|
* This function writes the TX calibration tables for the specified band to
|
|
* the EEPROM.
|
|
*
|
|
* @param [in] iBand
|
|
* GSM band (0:GSM-850, 1:GSM-900, 2:DCS-1800, 3:PCS-1900).
|
|
*
|
|
* @param [in] pTxCal
|
|
* Pointer to a TX calibration table structure.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_WriteTxCal( int iBand, const eeprom_TxCal_t *pTxCal )
|
|
{
|
|
int i;
|
|
int err;
|
|
int size;
|
|
int nArfcn;
|
|
eeprom_Cfg_t ee;
|
|
eeprom_SID_t sId;
|
|
eeprom_CfgTxCalV2_t *pCfgTxCal = NULL;
|
|
|
|
// Get a copy of the EEPROM header
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(ee.hdr), (char *) &ee.hdr );
|
|
if ( err != sizeof(ee.hdr) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the header magic ID
|
|
if ( ee.hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
// Init the header
|
|
ee.hdr.u32MagicId = EEPROM_CFG_MAGIC_ID;
|
|
ee.hdr.u16Version = EEPROM_HDR_V2;
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR, sizeof(ee.hdr) + sizeof(ee.cfg.v2), (const char *) &ee );
|
|
if ( err != sizeof(ee.hdr) + sizeof(ee.cfg.v2) )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
}
|
|
|
|
switch ( ee.hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
int32_t fixVal;
|
|
|
|
switch ( iBand )
|
|
{
|
|
case 0:
|
|
nArfcn = 124;
|
|
sId = EEPROM_SID_GSM850_TXCAL;
|
|
pCfgTxCal = &ee.cfg.v2.gsm850TxCalV2;
|
|
size = sizeof(ee.cfg.v2.gsm850TxCalV2) + sizeof(ee.cfg.v2.__gsm850TxCalMemV2);
|
|
break;
|
|
case 1:
|
|
nArfcn = 194;
|
|
sId = EEPROM_SID_GSM900_TXCAL;
|
|
pCfgTxCal = &ee.cfg.v2.gsm900TxCalV2;
|
|
size = sizeof(ee.cfg.v2.gsm900TxCalV2) + sizeof(ee.cfg.v2.__gsm900TxCalMemV2);
|
|
break;
|
|
case 2:
|
|
nArfcn = 374;
|
|
sId = EEPROM_SID_DCS1800_TXCAL;
|
|
pCfgTxCal = &ee.cfg.v2.dcs1800TxCalV2;
|
|
size = sizeof(ee.cfg.v2.dcs1800TxCalV2) + sizeof(ee.cfg.v2.__dcs1800TxCalMemV2);
|
|
break;
|
|
case 3:
|
|
nArfcn = 299;
|
|
sId = EEPROM_SID_PCS1900_TXCAL;
|
|
pCfgTxCal = &ee.cfg.v2.pcs1900TxCalV2;
|
|
size = sizeof(ee.cfg.v2.pcs1900TxCalV2) + sizeof(ee.cfg.v2.__pcs1900TxCalMemV2);
|
|
break;
|
|
default:
|
|
PERROR( "Invalid GSM band specified (%d)\n", iBand );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
pCfgTxCal->u16SectionID = sId;
|
|
pCfgTxCal->u16Crc = 0;
|
|
pCfgTxCal->u32Time = time(NULL);
|
|
|
|
//DSP firmware version
|
|
pCfgTxCal->u8DspMajVer = pTxCal->u8DspMajVer;
|
|
pCfgTxCal->u8DspMinVer = pTxCal->u8DspMinVer;
|
|
|
|
//FPGA firmware version
|
|
pCfgTxCal->u8FpgaMajVer = pTxCal->u8FpgaMajVer;
|
|
pCfgTxCal->u8FpgaMinVer = pTxCal->u8FpgaMinVer;
|
|
|
|
// Compress the calibration tables
|
|
for ( i = 0; i < 80; i++ )
|
|
{
|
|
fixVal = (int32_t)(pTxCal->fTxGainGmsk[i] * 32.f + (pTxCal->fTxGainGmsk[i]>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgTxCal->sfixTxGainGmsk[i] = 32767;
|
|
else if ( fixVal < -32768 ) pCfgTxCal->sfixTxGainGmsk[i] = -32768;
|
|
else pCfgTxCal->sfixTxGainGmsk[i] = (int16_t)fixVal;
|
|
}
|
|
fixVal = (int32_t)(pTxCal->fTx8PskCorr * 512.f + (pTxCal->fTx8PskCorr>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgTxCal->sfixTx8PskCorr = 32767;
|
|
else if ( fixVal < -32768 ) pCfgTxCal->sfixTx8PskCorr = -32768;
|
|
else pCfgTxCal->sfixTx8PskCorr = (int16_t)fixVal;
|
|
for ( i = 0; i < 31; i++ )
|
|
{
|
|
fixVal = (int32_t)(pTxCal->fTxExtAttCorr[i] * 512.f + (pTxCal->fTxExtAttCorr[i]>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgTxCal->sfixTxExtAttCorr[i] = 32767;
|
|
else if ( fixVal < -32768 ) pCfgTxCal->sfixTxExtAttCorr[i] = -32768;
|
|
else pCfgTxCal->sfixTxExtAttCorr[i] = (int16_t)fixVal;
|
|
}
|
|
for ( i = 0; i < nArfcn; i++ )
|
|
{
|
|
fixVal = (int32_t)(pTxCal->fTxRollOffCorr[i] * 512.f + (pTxCal->fTxRollOffCorr[i]>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgTxCal->sfixTxRollOffCorr[i] = 32767;
|
|
else if ( fixVal < -32768 ) pCfgTxCal->sfixTxRollOffCorr[i] = -32768;
|
|
else pCfgTxCal->sfixTxRollOffCorr[i] = (int16_t)fixVal;
|
|
}
|
|
|
|
// Add the CRC
|
|
pCfgTxCal->u16Crc = eeprom_crc( (uint8_t *)&pCfgTxCal->u32Time, size - 2 * sizeof(uint16_t) );
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR + ((uint8_t*)pCfgTxCal - (uint8_t*)&ee), size, (const char *)pCfgTxCal );
|
|
if ( err != size )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_ReadRxCal
|
|
************************************************************************//**
|
|
*
|
|
* This function reads the RX calibration tables for the specified band from
|
|
* the EEPROM.
|
|
*
|
|
* @param [in] iBand
|
|
* GSM band (0:GSM-850, 1:GSM-900, 2:DCS-1800, 3:PCS-1900).
|
|
*
|
|
* @param [in] iUplink
|
|
* Uplink flag (0:downlink, X:downlink).
|
|
*
|
|
* @param [inout] pRxCal
|
|
* Pointer to a RX calibration table structure.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_ReadRxCal( int iBand, int iUplink, eeprom_RxCal_t *pRxCal )
|
|
{
|
|
int i;
|
|
int size;
|
|
int nArfcn;
|
|
eeprom_Cfg_t *ee = eeprom_cached_config();
|
|
eeprom_SID_t sId;
|
|
eeprom_CfgRxCal_t *pCfgRxCal = NULL;
|
|
eeprom_CfgRxCalV2_t *pCfgRxCalV2 = NULL;
|
|
|
|
|
|
if (!ee)
|
|
{
|
|
PERROR( "Reading cached content failed.\n" );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
switch ( ee->hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V1:
|
|
{
|
|
switch ( iBand )
|
|
{
|
|
case 0:
|
|
nArfcn = 124;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_GSM850_RXUCAL;
|
|
pCfgRxCal = &ee->cfg.v1.gsm850RxuCal;
|
|
size = sizeof(ee->cfg.v1.gsm850RxuCal) + sizeof(ee->cfg.v1.__gsm850RxuCalMem);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_GSM850_RXDCAL;
|
|
pCfgRxCal = &ee->cfg.v1.gsm850RxdCal;
|
|
size = sizeof(ee->cfg.v1.gsm850RxdCal) + sizeof(ee->cfg.v1.__gsm850RxdCalMem);
|
|
}
|
|
break;
|
|
case 1:
|
|
nArfcn = 194;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_GSM900_RXUCAL;
|
|
pCfgRxCal = &ee->cfg.v1.gsm900RxuCal;
|
|
size = sizeof(ee->cfg.v1.gsm900RxuCal) + sizeof(ee->cfg.v1.__gsm900RxuCalMem);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_GSM900_RXDCAL;
|
|
pCfgRxCal = &ee->cfg.v1.gsm900RxdCal;
|
|
size = sizeof(ee->cfg.v1.gsm900RxdCal) + sizeof(ee->cfg.v1.__gsm900RxdCalMem);
|
|
}
|
|
break;
|
|
case 2:
|
|
nArfcn = 374;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_DCS1800_RXUCAL;
|
|
pCfgRxCal = &ee->cfg.v1.dcs1800RxuCal;
|
|
size = sizeof(ee->cfg.v1.dcs1800RxuCal) + sizeof(ee->cfg.v1.__dcs1800RxuCalMem);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_DCS1800_RXDCAL;
|
|
pCfgRxCal = &ee->cfg.v1.dcs1800RxdCal;
|
|
size = sizeof(ee->cfg.v1.dcs1800RxdCal) + sizeof(ee->cfg.v1.__dcs1800RxdCalMem);
|
|
}
|
|
break;
|
|
case 3:
|
|
nArfcn = 299;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_PCS1900_RXUCAL;
|
|
pCfgRxCal = &ee->cfg.v1.pcs1900RxuCal;
|
|
size = sizeof(ee->cfg.v1.pcs1900RxuCal) + sizeof(ee->cfg.v1.__pcs1900RxuCalMem);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_PCS1900_RXDCAL;
|
|
pCfgRxCal = &ee->cfg.v1.pcs1900RxdCal;
|
|
size = sizeof(ee->cfg.v1.pcs1900RxdCal) + sizeof(ee->cfg.v1.__pcs1900RxdCalMem);
|
|
}
|
|
break;
|
|
default:
|
|
PERROR( "Invalid GSM band specified (%d)\n", iBand );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
// Validate the ID
|
|
if ( pCfgRxCal->u16SectionID != sId )
|
|
{
|
|
PERROR( "Uninitialized data section\n" );
|
|
return EEPROM_ERR_UNAVAILABLE;
|
|
}
|
|
|
|
// Validate the CRC
|
|
if ( eeprom_crc( (uint8_t *)&pCfgRxCal->u32Time, size - 2 * sizeof(uint16_t) ) != pCfgRxCal->u16Crc )
|
|
{
|
|
PERROR( "Parity error\n" );
|
|
return EEPROM_ERR_PARITY;
|
|
}
|
|
|
|
// Expand the IQ imbalance mode (0:off, 1:on, 2:auto)
|
|
pRxCal->u8IqImbalMode = pCfgRxCal->u16IqImbalMode;
|
|
|
|
// Expand the IQ imbalance compensation
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pRxCal->u16IqImbalCorr[i] = pCfgRxCal->u16IqImbalCorr[i];
|
|
}
|
|
|
|
// Expand the External RX gain
|
|
pRxCal->fExtRxGain = (float)pCfgRxCal->sfixExtRxGain * 0.001953125f;
|
|
|
|
// Expand the Mixer gain error compensation
|
|
pRxCal->fRxMixGainCorr = (float)pCfgRxCal->sfixRxMixGainCorr * 0.001953125f;
|
|
|
|
// Expand the LNA gain error compensation (1:@-12 dB, 2:@-24 dB, 3:@-36 dB)
|
|
for ( i = 0; i < 3; i++ )
|
|
{
|
|
pRxCal->fRxLnaGainCorr[i] = (float)pCfgRxCal->sfixRxLnaGainCorr[i] * 0.001953125f;
|
|
}
|
|
|
|
// Expand the Frequency roll-off compensation
|
|
for ( i = 0; i < nArfcn; i++ )
|
|
{
|
|
pRxCal->fRxRollOffCorr[i] = (float)pCfgRxCal->sfixRxRollOffCorr[i] * 0.001953125f;
|
|
}
|
|
|
|
//DSP firmware version
|
|
pRxCal->u8DspMajVer = 0;
|
|
pRxCal->u8DspMinVer = 0;
|
|
|
|
//FPGA firmware version
|
|
pRxCal->u8FpgaMajVer = 0;
|
|
pRxCal->u8FpgaMinVer = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
switch ( iBand )
|
|
{
|
|
case 0:
|
|
nArfcn = 124;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_GSM850_RXUCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.gsm850RxuCalV2;
|
|
size = sizeof(ee->cfg.v2.gsm850RxuCalV2) + sizeof(ee->cfg.v2.__gsm850RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_GSM850_RXDCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.gsm850RxdCalV2;
|
|
size = sizeof(ee->cfg.v2.gsm850RxdCalV2) + sizeof(ee->cfg.v2.__gsm850RxdCalMemV2);
|
|
}
|
|
break;
|
|
case 1:
|
|
nArfcn = 194;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_GSM900_RXUCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.gsm900RxuCalV2;
|
|
size = sizeof(ee->cfg.v2.gsm900RxuCalV2) + sizeof(ee->cfg.v2.__gsm900RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_GSM900_RXDCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.gsm900RxdCalV2;
|
|
size = sizeof(ee->cfg.v2.gsm900RxdCalV2) + sizeof(ee->cfg.v2.__gsm900RxdCalMemV2);
|
|
}
|
|
break;
|
|
case 2:
|
|
nArfcn = 374;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_DCS1800_RXUCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.dcs1800RxuCalV2;
|
|
size = sizeof(ee->cfg.v2.dcs1800RxuCalV2) + sizeof(ee->cfg.v2.__dcs1800RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_DCS1800_RXDCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.dcs1800RxdCalV2;
|
|
size = sizeof(ee->cfg.v2.dcs1800RxdCalV2) + sizeof(ee->cfg.v2.__dcs1800RxdCalMemV2);
|
|
}
|
|
break;
|
|
case 3:
|
|
nArfcn = 299;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_PCS1900_RXUCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.pcs1900RxuCalV2;
|
|
size = sizeof(ee->cfg.v2.pcs1900RxuCalV2) + sizeof(ee->cfg.v2.__pcs1900RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_PCS1900_RXDCAL;
|
|
pCfgRxCalV2 = &ee->cfg.v2.pcs1900RxdCalV2;
|
|
size = sizeof(ee->cfg.v2.pcs1900RxdCalV2) + sizeof(ee->cfg.v2.__pcs1900RxdCalMemV2);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
PERROR( "Invalid GSM band specified (%d)\n", iBand );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
// Validate the ID
|
|
if ( pCfgRxCalV2->u16SectionID != sId )
|
|
{
|
|
PERROR( "Uninitialized data section\n" );
|
|
return EEPROM_ERR_UNAVAILABLE;
|
|
}
|
|
|
|
// Validate the CRC
|
|
if ( eeprom_crc( (uint8_t *)&pCfgRxCalV2->u32Time, size - 2 * sizeof(uint16_t) ) != pCfgRxCalV2->u16Crc )
|
|
{
|
|
PERROR( "Parity error - Band %d\n", iBand );
|
|
return EEPROM_ERR_PARITY;
|
|
}
|
|
|
|
// Expand the IQ imbalance mode (0:off, 1:on, 2:auto)
|
|
pRxCal->u8IqImbalMode = pCfgRxCalV2->u16IqImbalMode;
|
|
|
|
// Expand the IQ imbalance compensation
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pRxCal->u16IqImbalCorr[i] = pCfgRxCalV2->u16IqImbalCorr[i];
|
|
}
|
|
|
|
// Expand the External RX gain
|
|
pRxCal->fExtRxGain = (float)pCfgRxCalV2->sfixExtRxGain * 0.001953125;
|
|
|
|
// Expand the Mixer gain error compensation
|
|
pRxCal->fRxMixGainCorr = (float)pCfgRxCalV2->sfixRxMixGainCorr * 0.001953125;
|
|
|
|
// Expand the LNA gain error compensation (1:@-12 dB, 2:@-24 dB, 3:@-36 dB)
|
|
for ( i = 0; i < 3; i++ )
|
|
{
|
|
pRxCal->fRxLnaGainCorr[i] = (float)pCfgRxCalV2->sfixRxLnaGainCorr[i] * 0.001953125;
|
|
}
|
|
|
|
// Expand the Frequency roll-off compensation
|
|
for ( i = 0; i < nArfcn; i++ )
|
|
{
|
|
pRxCal->fRxRollOffCorr[i] = (float)pCfgRxCalV2->sfixRxRollOffCorr[i] * 0.001953125;
|
|
}
|
|
|
|
//DSP firmware version
|
|
pRxCal->u8DspMajVer = pCfgRxCalV2->u8DspMajVer;
|
|
pRxCal->u8DspMinVer = pCfgRxCalV2->u8DspMinVer;
|
|
|
|
//FPGA firmware version
|
|
pRxCal->u8FpgaMajVer = pCfgRxCalV2->u8FpgaMajVer;
|
|
pRxCal->u8FpgaMinVer = pCfgRxCalV2->u8FpgaMinVer;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function : eeprom_WriteRxCal
|
|
************************************************************************//**
|
|
*
|
|
* This function writes the RX calibration tables for the specified band to
|
|
* the EEPROM.
|
|
*
|
|
* @param [in] iBand
|
|
* GSM band (0:GSM-850, 1:GSM-900, 2:DCS-1800, 3:PCS-1900).
|
|
*
|
|
* @param [in] iUplink
|
|
* Uplink flag (0:downlink, X:downlink).
|
|
*
|
|
* @param [in] pRxCal
|
|
* Pointer to a RX calibration table structure.
|
|
*
|
|
* @return
|
|
* 0 if or an error core.
|
|
*
|
|
****************************************************************************/
|
|
eeprom_Error_t eeprom_WriteRxCal( int iBand, int iUplink, const eeprom_RxCal_t *pRxCal )
|
|
{
|
|
int i;
|
|
int err;
|
|
int size;
|
|
int nArfcn;
|
|
eeprom_Cfg_t ee;
|
|
eeprom_SID_t sId;
|
|
eeprom_CfgRxCalV2_t *pCfgRxCal = NULL;
|
|
|
|
// Get a copy of the EEPROM header
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(ee.hdr), (char *) &ee.hdr );
|
|
if ( err != sizeof(ee.hdr) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
|
|
// Validate the header magic ID
|
|
if ( ee.hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
// Init the header
|
|
ee.hdr.u32MagicId = EEPROM_CFG_MAGIC_ID;
|
|
ee.hdr.u16Version = EEPROM_HDR_V2;
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR, sizeof(ee.hdr) + sizeof(ee.cfg.v2), (const char *) &ee );
|
|
if ( err != sizeof(ee.hdr) + sizeof(ee.cfg.v2) )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
}
|
|
|
|
switch ( ee.hdr.u16Version )
|
|
{
|
|
case EEPROM_HDR_V2:
|
|
{
|
|
int32_t fixVal;
|
|
|
|
switch ( iBand )
|
|
{
|
|
case 0:
|
|
nArfcn = 124;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_GSM850_RXUCAL;
|
|
pCfgRxCal = &ee.cfg.v2.gsm850RxuCalV2;
|
|
size = sizeof(ee.cfg.v2.gsm850RxuCalV2) + sizeof(ee.cfg.v2.__gsm850RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_GSM850_RXDCAL;
|
|
pCfgRxCal = &ee.cfg.v2.gsm850RxdCalV2;
|
|
size = sizeof(ee.cfg.v2.gsm850RxdCalV2) + sizeof(ee.cfg.v2.__gsm850RxdCalMemV2);
|
|
}
|
|
break;
|
|
case 1:
|
|
nArfcn = 194;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_GSM900_RXUCAL;
|
|
pCfgRxCal = &ee.cfg.v2.gsm900RxuCalV2;
|
|
size = sizeof(ee.cfg.v2.gsm900RxuCalV2) + sizeof(ee.cfg.v2.__gsm900RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_GSM900_RXDCAL;
|
|
pCfgRxCal = &ee.cfg.v2.gsm900RxdCalV2;
|
|
size = sizeof(ee.cfg.v2.gsm900RxdCalV2) + sizeof(ee.cfg.v2.__gsm900RxdCalMemV2);
|
|
}
|
|
break;
|
|
case 2:
|
|
nArfcn = 374;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_DCS1800_RXUCAL;
|
|
pCfgRxCal = &ee.cfg.v2.dcs1800RxuCalV2;
|
|
size = sizeof(ee.cfg.v2.dcs1800RxuCalV2) + sizeof(ee.cfg.v2.__dcs1800RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_DCS1800_RXDCAL;
|
|
pCfgRxCal = &ee.cfg.v2.dcs1800RxdCalV2;
|
|
size = sizeof(ee.cfg.v2.dcs1800RxdCalV2) + sizeof(ee.cfg.v2.__dcs1800RxdCalMemV2);
|
|
}
|
|
break;
|
|
case 3:
|
|
nArfcn = 299;
|
|
if ( iUplink )
|
|
{
|
|
sId = EEPROM_SID_PCS1900_RXUCAL;
|
|
pCfgRxCal = &ee.cfg.v2.pcs1900RxuCalV2;
|
|
size = sizeof(ee.cfg.v2.pcs1900RxuCalV2) + sizeof(ee.cfg.v2.__pcs1900RxuCalMemV2);
|
|
}
|
|
else
|
|
{
|
|
sId = EEPROM_SID_PCS1900_RXDCAL;
|
|
pCfgRxCal = &ee.cfg.v2.pcs1900RxdCalV2;
|
|
size = sizeof(ee.cfg.v2.pcs1900RxdCalV2) + sizeof(ee.cfg.v2.__pcs1900RxdCalMemV2);
|
|
}
|
|
break;
|
|
default:
|
|
PERROR( "Invalid GSM band specified (%d)\n", iBand );
|
|
return EEPROM_ERR_INVALID;
|
|
}
|
|
|
|
pCfgRxCal->u16SectionID = sId;
|
|
pCfgRxCal->u16Crc = 0;
|
|
pCfgRxCal->u32Time = time(NULL);
|
|
|
|
//DSP firmware version
|
|
pCfgRxCal->u8DspMajVer = pRxCal->u8DspMajVer;
|
|
pCfgRxCal->u8DspMinVer = pRxCal->u8DspMinVer;
|
|
|
|
//FPGA firmware version
|
|
pCfgRxCal->u8FpgaMajVer = pRxCal->u8FpgaMajVer;
|
|
pCfgRxCal->u8FpgaMinVer = pRxCal->u8FpgaMinVer;
|
|
|
|
// Compress the IQ imbalance mode (0:off, 1:on, 2:auto)
|
|
pCfgRxCal->u16IqImbalMode = pRxCal->u8IqImbalMode;
|
|
|
|
// Compress the IQ imbalance compensation
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pCfgRxCal->u16IqImbalCorr[i] = pRxCal->u16IqImbalCorr[i];
|
|
}
|
|
|
|
// Compress the External RX gain
|
|
fixVal = (int32_t)(pRxCal->fExtRxGain * 512.f + (pRxCal->fExtRxGain>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgRxCal->sfixExtRxGain = 32767;
|
|
else if ( fixVal < -32768 ) pCfgRxCal->sfixExtRxGain = -32768;
|
|
else pCfgRxCal->sfixExtRxGain = (int16_t)fixVal;
|
|
|
|
// Compress the Mixer gain error compensation
|
|
fixVal = (int32_t)(pRxCal->fRxMixGainCorr * 512.f + (pRxCal->fRxMixGainCorr>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgRxCal->sfixRxMixGainCorr = 32767;
|
|
else if ( fixVal < -32768 ) pCfgRxCal->sfixRxMixGainCorr = -32768;
|
|
else pCfgRxCal->sfixRxMixGainCorr = (int16_t)fixVal;
|
|
|
|
// Compress the LNA gain error compensation (1:@-12 dB, 2:@-24 dB, 3:@-36 dB)
|
|
for ( i = 0; i < 3; i++ )
|
|
{
|
|
fixVal = (int32_t)(pRxCal->fRxLnaGainCorr[i] * 512.f + (pRxCal->fRxLnaGainCorr[i]>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgRxCal->sfixRxLnaGainCorr[i] = 32767;
|
|
else if ( fixVal < -32768 ) pCfgRxCal->sfixRxLnaGainCorr[i] = -32768;
|
|
else pCfgRxCal->sfixRxLnaGainCorr[i] = (int16_t)fixVal;
|
|
}
|
|
|
|
// Compress the Frequency roll-off compensation
|
|
for ( i = 0; i < nArfcn; i++ )
|
|
{
|
|
fixVal = (int32_t)(pRxCal->fRxRollOffCorr[i] * 512.f + (pRxCal->fRxRollOffCorr[i]>0 ? 0.5f:-0.5f));
|
|
if ( fixVal > 32767 ) pCfgRxCal->sfixRxRollOffCorr[i] = 32767;
|
|
else if ( fixVal < -32768 ) pCfgRxCal->sfixRxRollOffCorr[i] = -32768;
|
|
else pCfgRxCal->sfixRxRollOffCorr[i] = (int16_t)fixVal;
|
|
}
|
|
|
|
// Add the CRC
|
|
pCfgRxCal->u16Crc = eeprom_crc( (uint8_t *)&pCfgRxCal->u32Time, size - 2 * sizeof(uint16_t) );
|
|
|
|
// Write it to the EEPROM
|
|
err = eeprom_write( EEPROM_CFG_START_ADDR + ((uint8_t*)pCfgRxCal - (uint8_t*)&ee), size, (const char *)pCfgRxCal );
|
|
if ( err != size )
|
|
{
|
|
PERROR( "Error while writing to the EEPROM (%d)\n", err );
|
|
return EEPROM_ERR_DEVICE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PERROR( "Unsupported header version\n" );
|
|
return EEPROM_ERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
return EEPROM_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Private functions *
|
|
****************************************************************************/
|
|
|
|
/**
|
|
* Dump the content of the EEPROM to the standard output
|
|
*/
|
|
int eeprom_dump( int addr, int size, int hex )
|
|
{
|
|
FILE *f;
|
|
char ch;
|
|
int i;
|
|
|
|
f = fopen( EEPROM_DEV, "r+" );
|
|
if ( f == NULL )
|
|
{
|
|
perror( "eeprom fopen" );
|
|
return -1;
|
|
}
|
|
if (fseek( f, addr, SEEK_SET ) != 0)
|
|
{
|
|
perror( "eeprom fseek" );
|
|
fclose( f );
|
|
return -1;
|
|
}
|
|
|
|
for ( i = 0; i < size; ++i, ++addr )
|
|
{
|
|
if ( fread( &ch, 1, 1, f ) != 1 )
|
|
{
|
|
perror( "eeprom fread" );
|
|
fclose( f );
|
|
return -1;
|
|
}
|
|
if ( hex )
|
|
{
|
|
if ( (i % 16) == 0 )
|
|
{
|
|
printf( "\n %.4x| ", addr );
|
|
}
|
|
else if ( (i % 8) == 0 )
|
|
{
|
|
printf( " " );
|
|
}
|
|
printf( "%.2x ", ch );
|
|
}
|
|
else
|
|
putchar( ch );
|
|
}
|
|
if ( hex )
|
|
{
|
|
printf( "\n\n" );
|
|
}
|
|
fflush( stdout );
|
|
|
|
fclose( f );
|
|
return 0;
|
|
}
|
|
|
|
static FILE *g_file;
|
|
static eeprom_Cfg_t *g_cached_cfg;
|
|
|
|
void eeprom_free_resources(void)
|
|
{
|
|
if (g_file)
|
|
fclose(g_file);
|
|
g_file = NULL;
|
|
|
|
/* release the header */
|
|
free(g_cached_cfg);
|
|
g_cached_cfg = NULL;
|
|
}
|
|
|
|
/**
|
|
* Read up to 'size' bytes of data from the EEPROM starting at offset 'addr'.
|
|
*/
|
|
static int eeprom_read( int addr, int size, char *pBuff )
|
|
{
|
|
FILE *f = g_file;
|
|
int n;
|
|
|
|
if (!f) {
|
|
f = fopen( EEPROM_DEV, "r+" );
|
|
if ( f == NULL )
|
|
{
|
|
perror( "eeprom fopen" );
|
|
return -1;
|
|
}
|
|
g_file = f;
|
|
}
|
|
if (fseek( f, addr, SEEK_SET ) != 0)
|
|
{
|
|
perror( "eeprom fseek" );
|
|
return -1;
|
|
}
|
|
|
|
n = fread( pBuff, 1, size, f );
|
|
return n;
|
|
}
|
|
|
|
static void eeprom_cache_cfg(void)
|
|
{
|
|
int err;
|
|
|
|
free(g_cached_cfg);
|
|
g_cached_cfg = malloc(sizeof(*g_cached_cfg));
|
|
|
|
if (!g_cached_cfg)
|
|
return;
|
|
|
|
err = eeprom_read( EEPROM_CFG_START_ADDR, sizeof(*g_cached_cfg), (char *) g_cached_cfg );
|
|
if ( err != sizeof(*g_cached_cfg) )
|
|
{
|
|
PERROR( "Error while reading the EEPROM content (%d)\n", err );
|
|
goto error;
|
|
}
|
|
|
|
if ( g_cached_cfg->hdr.u32MagicId != EEPROM_CFG_MAGIC_ID )
|
|
{
|
|
PERROR( "Invalid EEPROM format\n" );
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
free(g_cached_cfg);
|
|
g_cached_cfg = NULL;
|
|
}
|
|
|
|
static eeprom_Cfg_t *eeprom_cached_config(void)
|
|
{
|
|
if (!g_cached_cfg)
|
|
eeprom_cache_cfg();
|
|
return g_cached_cfg;
|
|
}
|
|
|
|
/**
|
|
* Write up to 'size' bytes of data to the EEPROM starting at offset 'addr'.
|
|
*/
|
|
static int eeprom_write( int addr, int size, const char *pBuff )
|
|
{
|
|
FILE *f = g_file;
|
|
int n;
|
|
|
|
if (!f) {
|
|
f = fopen( EEPROM_DEV, "r+" );
|
|
if ( f == NULL )
|
|
{
|
|
perror( "eeprom fopen" );
|
|
return -1;
|
|
}
|
|
g_file = f;
|
|
}
|
|
if (fseek( f, addr, SEEK_SET ) != 0)
|
|
{
|
|
perror( "eeprom fseek" );
|
|
n = -1;
|
|
goto error;
|
|
}
|
|
|
|
n = fwrite( pBuff, 1, size, f );
|
|
|
|
error:
|
|
fclose( f );
|
|
g_file = NULL;
|
|
return n;
|
|
}
|
|
|
|
|
|
/**
|
|
* EEPROM CRC.
|
|
*/
|
|
static uint16_t eeprom_crc( uint8_t *pu8Data, int len )
|
|
{
|
|
int i;
|
|
uint16_t crc = 0xFFFF;
|
|
|
|
while (len--) {
|
|
crc ^= (uint16_t)*pu8Data++;
|
|
|
|
for (i=0; i<8; i++) {
|
|
if (crc & 1) crc = (crc >> 1) ^ 0x8408;
|
|
else crc = (crc >> 1);
|
|
}
|
|
}
|
|
|
|
crc = ~crc;
|
|
return crc;
|
|
}
|