/******************************************************************************
版权所有：	
文件名称：	adc.c
文件版本：	01.01
创建作者:	sunxi
创建日期：	2025-06-09
功能说明：	adc驱动程序。
其它说明：
修改记录：
*/

/*------------------------------ 头文件 ---------------------------------------
*/
#include "bsp.h"
#include "rt.h"
#include "head.h"
#include <malloc.h>
#include "rt_printf.h"
// #include "shm_comm_packet.h"
#include <mb.h>
#include "shmem.h"

/*------------------------------ 宏定义 ---------------------------------------
*/
#if CFG_BSP_DEBUG
#define _ADC_DEBUG
#endif

#define AC_HZ_NORMAL	50.0 // 交流标准频率


#define ADC_DOT_BUF_SIZE	((CFG_ADC_CHANNEL)*(CFG_ADC_DOTS_PER_CHANNEL*2)*2)




/*------------------------------ 全局变量 -------------------------------------
*/
// AD片选地址，8、9、10、11槽对应CS2、CS1、CS3、CS4。
static int g_adc_slot2cs[EQU_SLOT_AC_NUM] = {0};
static u8 g_adc_chip;
static u32 g_adc_range[EQU_SLOT_AC_NUM];

const u8 g_cs_channel_table[CFG_ADC_CHANNEL]={1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16};

//每个通道占用的空间:CFG_ADC_DOTS_PER_CHANNEL*2*2 = 128*2*2=512
//通道数:CFG_ADC_CHANNEL+2= 64+2=66
//总空间:512*18=9216=0x2400
//保证首地址是buf长度两倍的倍数。以利用MAC计算的MASK寄存器来达到
//循环buf的功能。注意每个通道buf的后半部分目前没有利用，以后可以用来干需要干的事情.
//通道加2，用作开入开出等状态保存。

// 不能使用分配的DMA内存，因为冷火实时linux平台不能使用动态内存映射。
//short (*g_adc_dots)[CFG_ADC_DOTS_PER_CHANNEL*2];
//s16 (*g_adc_dots)[CFG_ADC_DOTS_PER_CHANNEL*2] = (short (*)[CFG_ADC_DOTS_PER_CHANNEL*2])0x8ff00000;
s16 (*g_adc_dots)[CFG_ADC_DOTS_PER_CHANNEL*2];
struct timespec ts_adc_dots[CFG_ADC_DOTS_PER_CHANNEL];//时间戳

// 128点录波，32点计算
// 注意此buf由于是DMA类型，不能在实时中断中使用，只能在线程中使用。
//s16 g_adc_dots_rec[CFG_ADC_DOTS_PER_CHANNEL*4][CFG_ADC_CHANNEL];
s16 (*g_adc_dots_rec)[CFG_ADC_CHANNEL];
u32  g_adc_dots_rec_dma;

// 直流量测量采样点BUF
u16 g_adc_dots_dc[CFG_ADC_CHANNEL_DC][CFG_ADC_DOTS_PER_CHANNEL];

//ADC同步标志，表示ADC采样点BUFFER中的数据是否有效,AD7616转换的第一次数据也无效。
int g_adc_sync	= -(CFG_ADC_DOTS_PER_CHANNEL+1);

// ADC点BUF的索引，当前索引下无值。
volatile unsigned long g_adc_dots_count;
int g_adc_channel;
unsigned long g_adZero=14790;

char g_adc_name[CFG_ADC_CHANNEL_ALL][20];
struct rt_stat 	g_stat_adc[CFG_ADC_CHANNEL_ALL];

// 跟踪频率
float g_freq = 50.0 ;


// 直流量测量采样点BUF
u16 g_adc_dots_dc[CFG_ADC_CHANNEL_DC][CFG_ADC_DOTS_PER_CHANNEL];

uint32_t g_yx_buf[2] = {0xffffffff,0xffffffff}; //预留64个遥信


int g_adc_stat_flag=0;


volatile unsigned int adc_wp;
volatile unsigned int adc_rp;
bool prt_flag;

volatile unsigned long g_adc_dots_data_count;

SHM_VER_T LuoHe_version;





/*------------------------------ 函数声明 -------------------------------------
*/
void dido_di_poll(SHM_SAMPLE_T *sample_data);

/*------------------------------ 外部函数 -------------------------------------
*/

//设置各通道的参考电压
static int write_v_default(uint8_t no, uint8_t *data)
{
	int ret = 0;
	int cnt = 0;

	if(data == NULL)
		return -1;
		
    while(1)
    {
    	// ret = shm_comm_packet_write(SHM_ADDR_D_RFV_1+(SHM_ADDR_D_RFV_2-SHM_ADDR_D_RFV_1)*no, data, sizeof(SHM_RFV_T));
		if(ret > 0)	
		{
			break;
		}

		if(++cnt > 3)
			break;

        usleep(30);
    }
    return ret;
}


int adc_set_v_default(int no, u32 value)
{
	int ret = 0;
	SHM_RFV_T v;

	v.rc = value;
		
	ret = write_v_default(no,(uint8_t *)&v);

    return ret;
}

void adc_get_range_config(int no,int slot)
{
	int i,scale,channel,shift;
	u32 rc;

	rc = 0;
	for(i=0;i<EQU_SLOT_AC_CHN;i++)
	{
		channel = equ_get_ac_channel(slot,i)&0x0f;

		// 确定需要移位的数量
		// 双数是通道A，在低16位
		// 单数是通道B，在高16位
		shift = (channel/2)*2;
		if((channel&0x01))
		{
			shift += 16;	
		}
		if(channel == AD7616_DC0_CHANNEL || channel == AD7616_DC1_CHANNEL)
		{
			rc |= 2<<shift;// 5V
			continue;
		}
		scale = equ_get_ac_scale(slot,i);
		switch(scale)
		{
		case EQU_SCALE_PT_DEFAULT:
		case EQU_SCALE_PT_120K:
		case EQU_SCALE_PT_172K:
		case EQU_SCALE_PT_204K:
		case EQU_SCALE_CT_10A_51:
		case EQU_SCALE_CT_10A_120:
			rc |= 1<<shift; // 2.5V
		break;
		case EQU_SCALE_PT_102K:
		case EQU_SCALE_PT_120K_604:
		case EQU_SCALE_PT_264V_3V53:
		case EQU_SCALE_CT_100A_3V53:
		case EQU_SCALE_CT_DEFAULT:
		case EQU_SCALE_CT_10A_249:
		case EQU_SCALE_CT_10A_604:
		case EQU_SCALE_EVT_3V25_100V:
		case EQU_SCALE_PT_400V_3V53:
		case EQU_SCALE_CT_20A_3V53:
			rc |= 2<<shift;// 5V
		break;
		case EQU_SCALE_EVT_6V50_100V:
		case EQU_SCALE_ECT_1V_1A:
		case EQU_SCALE_ECT_0V2_1A: // 零序电子CT采用2.5V的范围
			rc |= 3<<shift; // 10V
		break;
		}
	}
	
	adc_set_v_default(no,rc);  
	mb_notice_RfV_update(0);

}

static int get_adc_wp(void)
{
    WP_T wp;
	int ret = 0;
	int cnt = 0;
		
    while(1)
    {
		ret = shm_comm_packet_read(SHM_ADDR_U_WP, sizeof(wp), (uint8_t *)&wp, sizeof(wp));
		if(ret > 0)	
		{
			return wp.write_flag_A;
		}

		if(++cnt > 3)
			break;

        usleep(30);
    }
    return ret;
}

static int get_adc_sample(uint32_t addr, int index, uint8_t *out_data)
{
    SHM_SAMPLE_T sample;
	int ret = 0;
	int cnt = 0;

	if(out_data == NULL)
		return -1;
		
    while(1)
    {
		ret = shm_comm_packet_read_noABcrc(addr + index*(sizeof(sample)), sizeof(sample), out_data, sizeof(sample));
		if(ret > 0)	
		{
			break;
		}

		if(++cnt > 3)
			break;

        usleep(30);
    }
    return ret;
}

static int get_e907_version(SHM_VER_T* par)
{
    SHM_VER_T ver;
	int ret = 0;
	int cnt = 0;

	if(par == NULL)
		return -1;
		
    while(1)
    {
		ret = shm_comm_packet_read(SHM_ADDR_U_VER, sizeof(ver), (uint8_t *)&ver, sizeof(ver));
		if(ret > 0)	
		{
			par->ver = ver.ver;
			par->v_crc = ver.v_crc;
			strcpy(par->time,ver.time);
			return 0;
		}

		if(++cnt > 3)
			break;

        usleep(30);
    }
    return -1;
}


int adc_init(void)
{
    int ret = 0;
	int i;

/*
	ret = get_adc_wp();
	if(ret < 0)
    {
        rt_printf("get_adc_wp 返回错误值，ret=%d!\r\n",adc_wp);
        return -1;
    }	
	adc_wp = adc_rp = ret;
*/

	memset(&LuoHe_version,0,sizeof(LuoHe_version));

	
    g_adc_dots_count=0;
	prt_flag=false;

    // 采样计算点BUF初始化
    // 32；周波数
    g_adc_dots = malloc(ADC_DOT_BUF_SIZE);
    if(g_adc_dots == NULL)
    {
        rt_printf("g_adc_dots 分配失败!\r\n");
        return -1;
    }

	memset(g_adc_dots, 0x55, ADC_DOT_BUF_SIZE);

    g_adc_dots_data_count=0;

    // 录波点BUF初始化
    // 32；周波数
    g_adc_dots_rec = malloc(CFG_ADC_CHANNEL*2*ADC_REC_DOTS_CHANNEL);
    if(g_adc_dots_rec == NULL)
    {
        rt_printf("g_adc_dots_rec 分配失败!\r\n");
		rt_free(g_adc_dots);
		g_adc_dots = NULL;
        return -1;
    }


	// 初始化统计变量
	for(i=0; i<CFG_ADC_CHANNEL_ALL; i++)
	{
		sprintf(g_adc_name[i],"adc%02d[%08lx]",i,(u32)g_adc_dots + i*sizeof(g_adc_dots[0]));
		rt_stat_init(&g_stat_adc[i],g_adc_name[i]);
	}

		
#if 0
	for(i=0; i<EQU_SLOT_AC_NUM; i++)   //配置通道的采样参数 直接写死 lch
	{
        printf("[%s:%d]\r\n", __func__, __LINE__);
		adc_get_range_config(i,g_ac_slot_begin+g_adc_slot2cs[i]);
	}

	// 检查和槽对应的ADC芯片是否安装或损坏
	//	printk("g_adc_chip=%02x.\r\n",g_adc_chip);
	for(i=0; i< EQU_SLOT_AC_NUM; i++)
	{
		if(equ_get_ac_num(g_ac_slot_begin+i))
		{
			if(adc_slot_is_ok(i) == 0)
			{
				 rt_err_set(ERR_CODE_INIT_ADC,i);
				 rt_printf("槽%02ld:ADC 芯片未安装或错误!\r\n",g_ac_slot_begin+i);
			}
		}
	}
#endif
    return ret;
}


int adc_exit(void)
{
    int ret=0;
	
    if(g_adc_dots_rec)
    {
       free(g_adc_dots_rec);
       g_adc_dots_rec=0;
    }
    if(g_adc_dots)
    {
       free(g_adc_dots);
       g_adc_dots=0;
    }
    
    return ret;
}

/**
 * @brief 旧方式获取共享内存数据（已抛弃）
 * 
 * @param mod 
 * @return int
 * @author zhl
 */
int adc_isr(int mod)
{

    int opt,i;
	SHM_SAMPLE_T sample_data[2];
	int ret = 0;
	int cnt = 0;
	int index = 0;
	static int start_flag = 0;
	static int recv_init = 0;
	static int get_version_flag = 0;

    ret = get_adc_wp();
	if(ret < 0)
	{
		// rt_printf("get_adc_wp 返回错误值, ret=%d!\r\n",ret);
		return -1;
	}

	if(get_version_flag == 0)
	{
		ret = get_e907_version(&LuoHe_version);
		if(ret == 0)
		{
			get_version_flag = 1;//noted by sunxi:这个应该要读成功后，才置为1.
			rt_printf("裸核版本号: ver=v%d.%02d,%s,crc=%X\r\n",LuoHe_version.ver/100,LuoHe_version.ver%100,LuoHe_version.time,LuoHe_version.v_crc);
		}
	}

	if(start_flag == 0)
	{
		//第1次运行，初始化 adc_rp
		start_flag++;
		adc_wp = ret;
		adc_rp = ret;

	}
	else
	{
		adc_wp = ret;
	}

	if(adc_wp>=SHM_ADC_WR_NUM)
	{
		adc_wp=0;
	}

	if(adc_rp>=SHM_ADC_WR_NUM)
	{
		adc_rp=0;
	}
		
    while(adc_wp!=adc_rp)
    {
        opt=((g_adc_dots_data_count&(ADC_REC_SAMPLE_RATE-1))==0)?TRUE:FALSE;

		ret = get_adc_sample(SHM_ADDR_U_ADC_1, adc_rp,(uint8_t *)&sample_data[0]);
		ret = get_adc_sample(SHM_ADDR_U_ADC_2, adc_rp,(uint8_t *)&sample_data[1]);
		if(ret < 0)
		{
			if(++cnt > 3)
			{
				rt_printf("get_adc_sample 返回错误值, ret=%d!\r\n",ret);
				break;
			}
			
			continue;

		}

		//保存yx值
		g_yx_buf[0] = sample_data[0].yx_buf[0];
		g_yx_buf[1] = sample_data[1].yx_buf[1];

		if(!recv_init)
		{
			recv_init = 1;
			//开机时裸核还没有把遥信送上下，这里重新初始化plc_init
			// dido_init_di();	//TODO EWen 集中式采用开入开出子板形式采集遥信
			// plc_init();		TODO EWen
		}

		// 标准化DTU遥信已经经过开入子板处理防抖
		// dido_di_poll(&sample_data[0]);
		
		for(i=0; i<16; i++)
        {
        	g_adc_dots_rec[g_adc_dots_index_rec][i] = sample_data[0].sample_buf[i];  
			
			
			if(opt==TRUE)
			{
            	g_adc_dots[i][g_adc_dots_index] = sample_data[0].sample_buf[i]; 
				ts_adc_dots[g_adc_dots_index] = sample_data[0].ts; 
			}
        }

		for(i=16; i<CFG_ADC_CHANNEL; i++)
        {
        	g_adc_dots_rec[g_adc_dots_index_rec][i] = sample_data[1].sample_buf[i - 16];  
			
			
			if(opt==TRUE)
			{
            	g_adc_dots[i][g_adc_dots_index] = sample_data[1].sample_buf[i - 16]; 
				ts_adc_dots[g_adc_dots_index] = sample_data[1].ts; 
			}
        }
		g_adc_dots_dc[0][g_adc_dots_data_count&CFG_ADC_DOTS_MASK] = sample_data[0].sample_buf[AD7616_DC0_CHANNEL];  
//		g_adc_dots_dc[1][g_adc_dots_data_count&CFG_ADC_DOTS_MASK] = sample_data.sample_buf[AD7616_DC0_CHANNEL];  
		
		if(opt==TRUE)
		{
			index = g_adc_dots_index;
			
			// 统计数据
			if(g_adc_stat_flag)
			{
				for(i=0; i<CFG_ADC_CHANNEL; i++)
				{
					rt_stat_in(&g_stat_adc[i],(unsigned short)(g_adc_dots[i][index]+32768));
				}
			}
			
			// 通道取反
			for(i=0; i<g_equ_adc_inv_num; i++)
			{
				g_adc_dots[g_equ_adc_inv[i]][index] = -(g_adc_dots[g_equ_adc_inv[i]][index]); 
			}
			
			
			// 全部BUFFER都是新数据，才能算同步好。
			if(g_adc_sync < 1)
			{
				g_adc_sync ++;
			}
			
			// 索引值加一
			g_adc_dots_count++;
			//保护计数+突变量
			{
				dTCounter++; 
				if(dTCounter%8==0) 
				{
					prt_flag=true;
				}
				//突变量					
				if(g_adc_sync == 1 && g_sw_init == 1)
				{
					protect_tbl_qd();	
				}
			}
		}
		
        g_adc_dots_data_count++;
		
        if(++adc_rp>=SHM_ADC_WR_NUM)
            adc_rp=0;

    }

	return 0;
}

static void updata_adc(struct t_shmdata_adc *sample_data0, uint16_t us_adc_dot_index0)
{
    int i = 0;
    int index = 0;
	static int mod = 0;
    int opt = ((g_adc_dots_data_count & (ADC_REC_SAMPLE_RATE - 1)) == 0) ? TRUE : FALSE;

    // 每片16路
    for (uint8_t j = 0; j < CFG_ADC_CHANNEL; j++)
    {
        g_adc_dots_rec[g_adc_dots_index_rec][j] = sample_data0->data.usa_sample_dots[j][us_adc_dot_index0];

        if (opt == TRUE)
        {
            g_adc_dots[j][g_adc_dots_index] = sample_data0->data.usa_sample_dots[j][us_adc_dot_index0];
        }
    }

    // 直流采样 国网集中式暂时不需要 zhl TODO
    // g_adc_dots_dc[0][g_adc_dots_data_count & CFG_ADC_DOTS_MASK] =
    // 	sample_data->data.usa_sample_dots[AD7616_DC0_CHANNEL][us_adc_dot_index];

    if (opt == TRUE)
    {
        index = g_adc_dots_index;

        // 统计数据
        if (g_adc_stat_flag)
        {
            for (i = 0; i < CFG_ADC_CHANNEL; i++)
            {
                rt_stat_in(&g_stat_adc[i], (unsigned short)(g_adc_dots[i][index] + 32768));
            }
        }

        // 通道取反
        for (i = 0; i < g_equ_adc_inv_num; i++)
        {
            g_adc_dots[g_equ_adc_inv[i]][index] = -(g_adc_dots[g_equ_adc_inv[i]][index]);
        }

        // 全部BUFFER都是新数据，才能算同步好。
        if (g_adc_sync < 1)
        {
            g_adc_sync++;
        }

        // 索引值加一
        g_adc_dots_count++;
        // 保护计数+突变量
        {
            dTCounter++;
            if (dTCounter % 8 == 0)
            {
                prt_flag = true;
            }
            // 突变量
            if (g_adc_sync == 1 && g_sw_init == 1)
            {
                protect_tbl_qd();
            }
        }
    }
#ifdef XDL_ZT
	xdl_tbl_qd(mod);
#endif
	mod++;
	mod &=(CFG_ADC_MOD_NUM-1);
    g_adc_dots_data_count++;
}

/**
 * @brief 新方式获取共享内存数据
 * 
 * @param mod 
 * @return int
 * @author zhl
 */
int adc_isr_new(int mod)
{
    int cnt = 0;
    struct t_shmdata_adc sample_data0 = {0};
    int ret0 = 0;
    int ret1 = 0;
    static volatile uint16_t smus_sample_read_index0 = 0; /* 读取adc1索引 */

    ret0 = shm_packet_read_v2(SHM_ADDR_W_U_ADC_1, sizeof(sample_data0), (uint8_t *)&sample_data0, sizeof(sample_data0));
    // printf("ret0=%d, sample_idx=%d, read_index=%d, us_updata=%d, us_op=%d, us_op_bk=%d\n",
    // 	ret0, sample_data0.data.us_sample_idx, smus_sample_read_index0, sample_data0.us_updata, sample_data0.us_op, sample_data0.us_op_bk);

    while (ret0 > 0)
    {
        if (++cnt > 5)
            break;

        usleep(300);
    }
    // printf("ret1=%d, sample_idx=%d, read_index=%d, us_updata=%d, us_op=%d, us_op_bk=%d\n",
    // 	ret1, sample_data1.data.us_sample_idx, smus_sample_read_index1, sample_data1.us_updata, sample_data1.us_op, sample_data1.us_op_bk);

    if (ret0 > 0 && (smus_sample_read_index0 != sample_data0.data.us_sample_idx))
    {
        uint16_t us_adc_dot_num0 = 0;
        if (sample_data0.data.us_sample_idx > smus_sample_read_index0)
        {
            us_adc_dot_num0 = sample_data0.data.us_sample_idx - smus_sample_read_index0;
        }
        else
        {
            us_adc_dot_num0 = (sample_data0.data.us_sample_idx + TC_ADC_DOTS_PER_CHANNEL) - smus_sample_read_index0;
        }
        // printf("us_adc_dot_num0:%d\n", us_adc_dot_num0);

        // us_adc_dot_num0 与 us_adc_dot_num1的数量一般相同
        for (uint16_t i = 0; i < us_adc_dot_num0; i++)
        {
            /* 注意采样下标索引不能超过采样缓存 TC_ADC_DOTS_PER_CHANNEL  */
            uint16_t us_adc_dot_index0 = (smus_sample_read_index0 + i) % TC_ADC_DOTS_PER_CHANNEL;

            // test zhl
            // int32_t physical_value0 = (int16_t)(sample_data0.data.usa_sample_dots[9][us_adc_dot_index0]);
            // printf("%d, ", physical_value0);
            // int32_t physical_value1 = (int16_t)(sample_data1.data.usa_sample_dots[1][us_adc_dot_index1]);
            // printf("%d, ", physical_value1);

            updata_adc(&sample_data0, us_adc_dot_index0);
        }

        smus_sample_read_index0 = (smus_sample_read_index0 + us_adc_dot_num0) % TC_ADC_DOTS_PER_CHANNEL;
    }

    return 0;
}

/******************************************************************************
函数名称：	adc_slot_is_ok
函数版本：	01.01
创建作者:	sunxi
创建日期：	2016-02-01
函数说明：	检查对应槽的ADC芯片是否安装或损坏。
参数说明：
	slot:	0~3；从g_ac_slot_begin开始
返回值：  	成功返回0.
修改记录：
*/
int adc_slot_is_ok(int slot)
{
	if((u32)slot >= EQU_SLOT_AC_NUM)
	{
		return 0;
	}

	if(g_adc_chip & (1<<g_adc_slot2cs[slot]))
	{
		return 1;
	}

	return 0;
}



/******************************************************************************
函数名称：	adc_fourier_address
函数版本：	01.01
创建作者：	sunxi
创建日期：	2008-06-26
函数说明：	返回指定的通道进行傅立叶计算的首地址。首地址保证4bytes对齐。
参数说明：
	channel：ADC的通道，取值0～7。
	index：	要进行傅立叶计算的32点中的最后一个点的索引。这么设置是为了和
			g_adc_dots_index匹配。保证g_adc_dots_index可以直接作为参数传进来。
返回值：  	成功返回0.
修改记录：	
*/
#if 0
short * adc_fourier_address(int channel,int index)
{
	short *p;
	
	//{index + CFG_ADC_DOTS_PER_CHANNEL}是为了确保索引在相应的范围之内.
	index = index + CFG_ADC_DOTS_PER_CHANNEL - CFG_ADC_DOTS_PER_PERIOD;
	
	//使用偶数索引,保证4bytes对齐
	index &= (~0x1);
	
	//得到首地址，注意地址必须和CFG_ADC_BUF_MASK相与。
	p = (short *)&g_adc_dots[channel][index];
	p = (short *)((unsigned int)p&CFG_ADC_BUF_MASK);
	
	return p;
}
#else
short sam_buf[CFG_ADC_CHANNEL][CFG_ADC_DOTS_PER_PERIOD];
short * adc_fourier_address(int channel,int index)
{
  short *p;
  int i;


  if(index >= CFG_ADC_DOTS_PER_PERIOD)
  {
	  index = index - CFG_ADC_DOTS_PER_PERIOD;
	  index &= (~0x1);
	  p = (short *)&g_adc_dots[channel][index];
  }
  else
  {
	  index = CFG_ADC_DOTS_PER_CHANNEL-CFG_ADC_DOTS_PER_PERIOD+index;
	  index &= (~0x1);
	  for(i = 0;i < CFG_ADC_DOTS_PER_CHANNEL - index;i++)
	  {
		  sam_buf[channel][i] = g_adc_dots[channel][index+i];
	  }

	  for(i = 0;i <CFG_ADC_DOTS_PER_PERIOD +index-CFG_ADC_DOTS_PER_CHANNEL;i++)
	  {
		  sam_buf[channel][i+CFG_ADC_DOTS_PER_CHANNEL - index] = g_adc_dots[channel][i];
	  }

	  p = sam_buf[channel];
  }

  return p;
  
}

#endif

 /******************************************************************************
函数名称：	adc_fourier_address_half
函数版本：	01.01
创建作者：	sunxi
创建日期：	2008-06-26
函数说明：	返回指定的通道进行傅立叶计算的首地址。首地址保证4bytes对齐。
参数说明：
	channel：ADC的通道，取值0～7。
	index：	要进行傅立叶计算的32点中的最后一个点的索引。这么设置是为了和
			g_adc_dots_index匹配。保证g_adc_dots_index可以直接作为参数传进来。
返回值：  	成功返回0.
修改记录：	
*/
short * adc_fourier_address_half(int channel,int index)
{
	short *p;
	
	//{index - (CFG_ADC_DOTS_PER_PERIOD - 1)}是因为索引下有实际的采样值，所以不是
	// index - CFG_ADC_DOTS_PER_PERIOD.
	//{index + CFG_ADC_DOTS_PER_CHANNEL}是为了确保索引在相应的范围之内.
	index = index + CFG_ADC_DOTS_PER_CHANNEL - (CFG_ADC_DOTS_PER_PERIOD/2 - 1);
	
	//使用偶数索引,保证4bytes对齐
	index &= (~0x1);
	
	//得到首地址，注意地址必须和CFG_ADC_BUF_MASK相与。
	p = (short *)&g_adc_dots[channel][index];
	p = (short *)((unsigned int)p&CFG_ADC_BUF_MASK);
	
	return p;
}

int adc_stat_printf(void)
{
	int i;
	unsigned long avg = 0;
	struct rt_stat *stat;

	if(g_adc_stat_flag == 0)
	{
		g_adc_stat_flag = 1;
		rt_printf("\r\n!!!ADC采样统计启动, 执行reset命令关闭。!!!\r\n");
	}

	rt_printf("\r\n频率跟踪:%fHZ.\r\n",g_freq);
	rt_printf("g_adc_chip:0x%02x.\r\n",g_adc_chip);
	for(i=0;i<EQU_SLOT_AC_NUM;i++)
	{
		rt_printf("槽[%02lu]: 是否有对应芯片:%d,输入范围:0x%08lx.\r\n",g_ac_slot_begin+i,adc_slot_is_ok(i),g_adc_range[g_adc_slot2cs[i]]);
	}

	rt_printf("\r\n[ADC中断周期统计]\r\n");
	rt_printf("name\t\t\tmin\tmax\tavg\tsum\t\tcnt\n");
//	rt_stat_printf(&g_stat_adc_time);

	rt_printf("\r\n[ADC抖动统计]\r\n");
	rt_printf("name\t\t\tmin\tmax\tdif\tavg\tsum\t\tcnt\n");

	rt_printf("\r\n");
	for(i=0; i<CFG_ADC_CHANNEL_ALL; i++)
	{
		stat = &g_stat_adc[i];
		if(stat->cnt)
		{
			avg = stat->sum/stat->cnt;
		}

		rt_printf("%-24s%ld\t%ld\t%ld\t%ld\t%-16ld%ld\r\n",stat->name,stat->min,stat->max,stat->max - stat->min,avg,stat->sum,stat->cnt);

	}

	return 0;
}

int adc_stat_reset(void)
{
	int i;

	g_adc_stat_flag = 0;

	for(i=0; i<CFG_ADC_CHANNEL_ALL; i++)
	{
		rt_stat_init(&g_stat_adc[i],g_stat_adc[i].name);
	}

//	rt_stat_init(&g_stat_adc_time,g_stat_adc_time.name);
	return 0;

}
#if 0
static int get_adc_dc(uint8_t *out_data)
{
	int ret = 0;
	int cnt = 0;

	if(out_data == NULL)
		return -1;
		
    while(1)
    {
		ret = shm_comm_packet_read(SHM_ADDR_U_DC, sizeof(SHM_DC_T), out_data, sizeof(SHM_DC_T));
		if(ret > 0)	
		{
			break;
		}

		if(++cnt > 3)
			break;

        usleep(30);
    }
    return ret;
}
#endif

float dc_get(unsigned int index)
{
	u32 i,v;
	float f;
	
	v = 0;
	for(i=0;i<CFG_ADC_DOTS_PER_CHANNEL;i++)
	{
		v += (u16)g_adc_dots_dc[index][i];
	}

	f = (float)v/CFG_ADC_DOTS_PER_CHANNEL;
	// 乘理论系数
	f /= 129.791f;

	return f;
}



/*------------------------------ 测试函数 -------------------------------------
*/
#ifdef _ADC_DEBUG
int adc_test(void)
{
	return 0;
}
#endif
/*------------------------------ 文件结束 -------------------------------------
*/
