8、实时数据备份和实时时钟功能实现

\qquad 下面是HD-GR GNSS导航软件的实时数据备份和实时时钟功能实现代码:

// rtc.c -- Real time data backup and RTC functions.

/* 
 * Copyright (C) 2005 Andrew Greenberg
 * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 (June 1991).
 * See the "COPYING" file distributed with this software for more information.
 */

/* 
 * HD-GR GNSS receiver project
 * Modes    : None
 * version  : V1.0
 * date     : xx/xx/2015
 */

#include <io.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "includes.h"
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#include "sys/alt_flash.h"
#include "sys/alt_sys_wrappers.h"
#include "rtc.h"

#define FLASH_BACKUP_REG	0
#define FLASH_BACKUP_OFS	0x200000

// DS32X35 RTC slave address
#define DS32X35_RTC_SLAVE_ADDRESS		0xd0

int m_rtc_inited = 0;
static int m_ic_ack = 0;

int flash_read_backup(int offset,void* dest_addr,int length)
{
    
    
	int ret_code = -1;
	alt_flash_fd* fd = alt_flash_open_dev(EPCS_FLASH_CONTROLLER_0_NAME);

	if (fd) {
    
    
		flash_region* regions;
		int number_of_regions;

		ret_code = alt_get_flash_info(fd, &regions, &number_of_regions);
		if ((ret_code == 0) && (number_of_regions > FLASH_BACKUP_REG)) {
    
    
			offset += FLASH_BACKUP_OFS;
			ret_code = alt_read_flash(fd,
					regions[FLASH_BACKUP_REG].offset+offset,
					dest_addr,length);
		}
		alt_flash_close_dev(fd);
	}
	return ret_code;
}

int flash_write_backup(int offset,void* dest_addr,int length)
{
    
    
	int ret_code = -1;
	alt_flash_fd* fd = alt_flash_open_dev(EPCS_FLASH_CONTROLLER_0_NAME);
	if (fd) {
    
    
		flash_region* regions;
		int number_of_regions;

		ret_code = alt_get_flash_info(fd, &regions, &number_of_regions);
		if ((ret_code == 0) && (number_of_regions > FLASH_BACKUP_REG)) {
    
    
			offset += FLASH_BACKUP_OFS;
			ret_code = alt_write_flash_block(fd,
					regions[FLASH_BACKUP_REG].offset,
					regions[FLASH_BACKUP_REG].offset+offset,
					dest_addr,length);
		}
		alt_flash_close_dev(fd);
	}
	return ret_code;
}

int cycgps_init_backup(void)
{
    
    
	int ret_code = -1;
	flash_backup_t *pfb = (flash_backup_t *)malloc(sizeof(flash_backup_t));

	memset(m_gps_alm, 0, sizeof(m_gps_alm));
	if (pfb) {
    
    
		if (flash_read_backup(0, pfb, sizeof(flash_backup_t)) == 0) {
    
    
			if (pfb->header.signature == BACKUP_HEADER_SIGNATURE &&
				pfb->header.data_size == sizeof(flash_backup_t)) {
    
    
				m_current_pvt = pfb->body.rec_pvt;
				m_current_neu = pfb->body.rec_neu;
				memcpy(m_gps_alm, pfb->body.gps_alm, sizeof(m_gps_alm));
				ret_code = 0;
			}
		}
		free(pfb);
	}
	return ret_code;
}

int cycgps_save_backup(void)
{
    
    
	int ret_code = -1;
	flash_backup_t *pfb = (flash_backup_t *)malloc(sizeof(flash_backup_t));

	if (pfb) {
    
    
		pfb->header.signature = BACKUP_HEADER_SIGNATURE;
		pfb->header.data_size = sizeof(flash_backup_t);
		pfb->header.data_time = get_standard_time();
		pfb->body.rec_pvt = m_current_pvt;
		pfb->body.rec_neu = m_current_neu;
		memcpy(pfb->body.gps_alm, m_gps_alm, sizeof(m_gps_alm));
		ret_code = flash_write_backup(0, pfb, sizeof(flash_backup_t));
		free(pfb);
	}
	return ret_code;
}


/*
 * Name: iic_start
 * Description: IIC启动
 */
void iic_start(void)
{
    
    
	// 发送启动条件的数据信号
	IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 1);
	// 发送启动条件的时钟信号
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
	// 启动条件建立时间大于4.7us延时
	ALT_USLEEP(10);
	// 发送启动信号
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 0);
	// 启动条件保持时间大于4us
	ALT_USLEEP(5);
	// 钳住IIC总线,准备发送或接收数据
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
	ALT_USLEEP(5);
}

/*
 * Name: iic_stop
 * Description: IIC停止
 */
void iic_stop(void)
{
    
    
	// 发送停止条件的数据信号
	IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 0);
	// 发送停止条件的时钟信号
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
	ALT_USLEEP(10);
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
	// 停止条件建立时间大于4us
	ALT_USLEEP(5);
	// 发送停止信号
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 1);
	ALT_USLEEP(10);
}

/*
 * Name: iic_write
 * Description: IIC写一个字节
 */
void iic_write(alt_u8 dat)
{
    
    
	alt_u8 i, tmp;

	IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
	for(i=0; i<8; i++) {
    
    
		// 发送数据位
		tmp = (dat & 0x80) ? 1 : 0;
		dat <<= 1;
		IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, tmp);
		ALT_USLEEP(5);
		// 置时钟线为高,通知受控器开始接收数据位
		IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
		// 保证时钟高电平周期大于4us
		ALT_USLEEP(10);
		IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
		ALT_USLEEP(5);
	}
	// 8位发送完后释放数据线,准备接收应答位
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 1);
	ALT_USLEEP(5);
	IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 0);
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
	ALT_USLEEP(5);
	// 接收应答位
	tmp = IORD_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE);
	m_ic_ack = (tmp == 1) ? 0:1;
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
	ALT_USLEEP(5);
}

/*
 * Name: iic_read
 * Description: IIC读一个字节
 */
alt_u8 iic_read(void)
{
    
    
	alt_u8 i, dat = 0;

	IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 0);
	for(i=0; i<8; i++) {
    
    
		// 置时钟线为低,准备接收数据位
		IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
		// 时钟低电平周期大于4.7us
		ALT_USLEEP(10);
		// 置时钟线为高,使数据线上数据有效
		IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
		ALT_USLEEP(5);
		// 读数据位
		dat <<= 1;
		dat |= IORD_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE);
		ALT_USLEEP(5);
	}
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
	ALT_USLEEP(5);
	return dat;
}

/*
 * Name: iic_ack
 * Description: 发出IIC应答或非应答信号
 */
void iic_ack(int a)
{
    
    
	// 发出应答或非应答信号
	IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, (a == 0)? 0:1);
	ALT_USLEEP(5);
	// 时钟高电平周期大于4us
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
	ALT_USLEEP(5);
	// 清时钟线,钳住IIC总线以便继续接收
	IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
	ALT_USLEEP(5);
}

/*
 * Name: rtc_write_byte
 * Description: 向RTC写一个字节
 * Return: 1表示成功
 */
int rtc_write_byte(alt_u8 addr, alt_u8 dat)
{
    
    
	// 启动总线
	iic_start();
	// 发送器件地址
	iic_write(addr);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 发送数据
	iic_write(dat);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 结束总线
	iic_stop();
	return 1;
}

/*
 * Name: rtc_write_multibytes
 * Description: 向RTC写多个字节
 * Return: 1表示成功
 */
int rtc_write_multibytes(alt_u8 addr, alt_u8 suba, alt_u8 *dat, int no)
{
    
    
	int i;

	// 启动总线
	iic_start();
	// 发送器件地址
	iic_write(addr);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 发送器件子地址
	iic_write(suba);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 发送数据
	for (i = 0; i < no; i ++) {
    
    
		iic_write(dat[i]);
		if (m_ic_ack == 0) {
    
    
			return 0;
		}
	}
	// 结束总线
	iic_stop();
	return 1;
}

/*
 * Name: rtc_read_byte
 * Description: 从RTC读一个字节
 * Return: 1表示成功
 */
int rtc_read_byte(alt_u8 addr, alt_u8 *c)
{
    
    
	// 启动总线
	iic_start();
	// 发送器件地址
	iic_write(addr+1);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 读取数据
	*c = iic_read();
	// 发送非应答位
	iic_ack(1);
	iic_stop();
	return 1;
}

/*
 * Name: rtc_read_multibytes
 * Description: 从RTC读多个字节
 * Return: 1表示成功
 */
int rtc_read_multibytes(alt_u8 addr, alt_u8 suba, alt_u8 *dat, int no)
{
    
    
	int i;

	// 启动总线
	iic_start();
	// 发送器件地址
	iic_write(addr);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 发送器件子地址
	iic_write(suba);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	iic_start();
	iic_write(addr+1);
	if (m_ic_ack == 0) {
    
    
		return 0;
	}
	// 接收数据
	for (i = 0; i < no-1; i ++) {
    
    
		// 接收字节
		dat[i]= iic_read();
		// 发送应答位
		iic_ack(0);
	}
	dat[i]= iic_read();
	// 发送非应答位
	iic_ack(1);
	iic_stop();
	return 1;
}

/*
 * Description: 设置时间信息
 * Return: 1表示成功
 */
int ds32x35_set_time(stdtime_t st, double gsts)
{
    
    
	alt_u8 val, ti[7];

	val = (alt_u8)st.seconds;
	ti[0] = ((val/16) << 4) + val%16;
	ti[1] = (alt_u8)(((st.minutes/16) << 4) + st.minutes%16);
	ti[2] = (alt_u8)(((st.hours/16) << 4) + st.hours%16);
	ti[3] = (alt_u8)((int)gsts/86400) + 1;
	ti[4] = (alt_u8)(((st.days/16) << 4) + st.days%16);
	ti[5] = (alt_u8)(((st.months/16) << 4) + st.months%16);
	val = (alt_u8)(st.years - 2000);
	ti[6] = ((val/16) << 4) + val%16;
	return rtc_write_multibytes(DS32X35_RTC_SLAVE_ADDRESS, 0, ti, 7);
}

/*
 * Description: 获取时间信息
 * Return: 1表示成功
 */
int ds32x35_get_time(stdtime_t *pst)
{
    
    
	int result;
	alt_u8 ti[7];

	result = rtc_read_multibytes(DS32X35_RTC_SLAVE_ADDRESS, 0, ti, 7);
	if (result != 0) {
    
    
		if (ti[6] == 0) {
    
    
			result = 0;
		}
		else if (pst) {
    
    
			pst->seconds= (ti[0] >> 4)*10 + ti[0]%16;
			pst->minutes= (ti[1] >> 4)*10 + ti[1]%16;
			pst->hours	= (ti[2] >> 4)*10 + ti[2]%16;
			pst->days	= (ti[4] >> 4)*10 + ti[4]%16;
			pst->months = (ti[5] >> 4)*10 + ti[5]%16;
			pst->years	= (ti[6] >> 4)*10 + ti[6]%16 + 2000;
		}
	}
	return result;
}

/*
 * Description: 检查时间设置情况,如果未设置,可能时进行设置
 * Return: 1表示进行了设置, 0表示保持现有设置,-1表示错误
 */
int ds32x35_check_set_time(void)
{
    
    
	if (m_rtc_inited == 0 && get_clock_state() >= SF1_CLOCK) {
    
    
		int result = ds32x35_set_time(
				get_standard_time(),
				get_time_in_seconds());
		m_rtc_inited = (result > 0) ? 1:-1;
	}
	return m_rtc_inited;
}

猜你喜欢

转载自blog.csdn.net/turing321_huaide/article/details/118939588