/******************************************************************************
** Copyright 2015 MBARI - Monterey Bay Aquarium Research Institute
*******************************************************************************
*******************************************************************************
** Summary  : Routines to access DS3234 Accurate RTC with SRAM
** Filename : ds1683.c
** Author   : Luke Coletti
** Project  :
** Version  : 1.0
** Compiler : MetroWerks Code Warrior v8.3
** Created  : 12/15/14
** Archived :
*******************************************************************************
** Modification History:
** 01/02/15 : CF2 Port, LJC	(from HEBO supplied BEDS code)
*******************************************************************************/

#include        <cfxpico.h>                     /* Persistor PicoDOS definitions    */
#include        <ds3234.h>


extern time_t DS3234_secs;                          /* DS3234 time of day	*/
extern struct tm DS3234_tm;                             /* DS3234 time of day as struct tm*/


int DS3234_Init(void)
{
	ushort rtcRegs[4];

	spiInitRTC();

	if( DS3234_InitTime() ) {
		RTCSetTime(DS3234_secs, 0);
	}
	else{
		printf("\nBogus time in accurate RTC!!! Setting to Y2K\n");
		DS3234_SetTime(946684800UL);
		RTCSetTime(946684800UL, 0);
	}

	// set Alarm Rate to match date, hours, minutes and seconds (even if we won't be using the DS3234 for alarms)
	rtcRegs[0] = rtcRegs[1] = rtcRegs[2] = rtcRegs[3] = 0x00;
	spiWriteMultRTCRegs(RTC_ALM1_SEC, 4, rtcRegs);

	// set Interrupt Control (INT/SQW pin) to match Alarm but disable both A1 and A2
	spiWriteRTCReg(RTC_CTRL, 4);

	// enable 32kHz output pin (measured at TP5) and set temp conversion rate to 512 secs (slowest rate to conserve power - see Maxim AppNote 3644)
	spiWriteRTCReg(RTC_CTRLSTAT, 0x38);

	return( OK );

}


int DS3234_InitTime(void)
{
	ushort rtcRegs[7];

	spiReadMultRTCRegs(RTC_SEC, 7, rtcRegs);

	DS3234_tm.tm_sec = fromBCD(rtcRegs[0]);
	DS3234_tm.tm_min = fromBCD(rtcRegs[1]);
	DS3234_tm.tm_hour = fromBCD(rtcRegs[2]);
	DS3234_tm.tm_mday = fromBCD(rtcRegs[4]);
	DS3234_tm.tm_mon = fromBCD(rtcRegs[5]) - 1;
	DS3234_tm.tm_year = fromBCD(rtcRegs[6]) + 100;

	if ((DS3234_tm.tm_mon > 11) || (DS3234_tm.tm_mday < 1) ||
	    (DS3234_tm.tm_mday > 31) || (DS3234_tm.tm_hour > 23) ||
	    (DS3234_tm.tm_min >= 60) || (DS3234_tm.tm_sec > 60))
	{
		return(FALSE);
	}

	DS3234_tm.tm_wday = 0;
	DS3234_tm.tm_yday = 0;
	DS3234_tm.tm_isdst = 0;
	if ((DS3234_secs = mktime(&DS3234_tm)) == (time_t)(-1))
		return(FALSE);

	return(TRUE);

}


time_t DS3234_GetTime(void)
{
	ushort rtcRegs[7];

	spiReadMultRTCRegs(RTC_SEC, 7, rtcRegs);

	DS3234_tm.tm_sec = fromBCD(rtcRegs[0]);
	DS3234_tm.tm_min = fromBCD(rtcRegs[1]);
	DS3234_tm.tm_hour = fromBCD(rtcRegs[2]);
	DS3234_tm.tm_mday = fromBCD(rtcRegs[4]);
	DS3234_tm.tm_mon = fromBCD(rtcRegs[5]) - 1;
	DS3234_tm.tm_year = fromBCD(rtcRegs[6]) + 100;

	DS3234_tm.tm_wday = 0;
	DS3234_tm.tm_yday = 0;
	DS3234_tm.tm_isdst = 0;

	DS3234_secs = mktime(&DS3234_tm);

	return(DS3234_secs);

}


void DS3234_SetTime(time_t now)
{
	ushort rtcRegs[7];
	struct tm   *tmp = gmtime(&now);

	rtcRegs[0] = toBCD(tmp->tm_sec) & 0x7f;
	rtcRegs[1] = toBCD(tmp->tm_min) & 0x7f;
	rtcRegs[2] = toBCD(tmp->tm_hour) & 0x3f;
	rtcRegs[3] = (tmp->tm_wday & 7) + 1;
	rtcRegs[4] = toBCD(tmp->tm_mday) & 0x3f;
	rtcRegs[5] = toBCD(tmp->tm_mon + 1) & 0x1f;
	rtcRegs[6] = toBCD(tmp->tm_year % 100);

	spiWriteMultRTCRegs(RTC_SEC, 7, rtcRegs);

}


int DS3234_RdSRAM(ushort ADDR, ushort DATBYTES, void *vp)
{
	uchar val[4];
	ushort rtc[4];
	int i;


	if( ( (DATBYTES != 1) && (DATBYTES != 2) && (DATBYTES != 4) ) || (vp == NULL) )
		return( ERROR );

	spiWriteRTCReg(RTC_ADDR, ADDR);

	spiReadMultRTCRegs(RTC_DATA, DATBYTES, rtc);

	//68k uP is big-endian (MSB at lowest mem addr)
	for(i = 0; i < DATBYTES; i++ )
		val[i] = (uchar) (rtc[i] & 0x00FF);

	// synthesize value from byte array.
	memcpy(vp, (uchar*)val, (size_t)DATBYTES);

	return( OK );

}

int DS3234_WrSRAM(ushort ADDR, ushort DATBYTES, void *vp)
{
	uchar val[4];
	ushort rtc[4];
	int i;


	if( ( (DATBYTES != 1) && (DATBYTES != 2) && (DATBYTES != 4) ) || (vp == NULL) )
		return( ERROR );

	// decompose value into byte array.
	memcpy((uchar*)val, vp, (size_t)DATBYTES);

	//68k uP is big-endian (MSB at lowest mem addr)
	for(i = 0; i < DATBYTES; i++ )
		rtc[i] = (ushort) val[i];

	spiWriteRTCReg(RTC_ADDR, ADDR);

	spiWriteMultRTCRegs(RTC_DATA, DATBYTES, rtc);

	return( OK );

}

float DS3234_GetTemp(void)
{
	uchar temp_h, temp_l;
	int nint;
	float temp;

	//test BSY bit then initiate a temp conversion (could be implemented, or not...)

	temp_h = spiReadRTCReg(RTC_TEMP);
	temp_l = spiReadRTCReg(RTC_TEMPL) >> 6;

	if( (temp_h & 0x80) != 0 )
		nint = temp_h | ~((1 << 8) - 1);  // if negative get two's complement
	else
		nint = temp_h;

	temp = (float)nint + (0.25 * (float)temp_l);

	return( temp );

}

ushort toBCD(ushort inw)
{
	return((((inw/10)%10) << 4) | (inw%10));
}


ushort fromBCD(ushort bcd)
{
	return(10*((bcd >> 4) & 0xf) + (bcd & 0xf));
}

