/************************************************************************** * * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file RTC.c * * @date 27-Nov-2019 * @author D. Navaei * * @brief Monitor/Controller Real Time Clock * **************************************************************************/ #include "Common.h" #include "Timers.h" #include "RTC.h" #include "mibspi.h" // ********** private definitions ********** #define RTC_REG_1_12_HOUR_MODE 0X0004 #define RTC_REG_1_PORO 0X0008 #define RTC_REG_1_CLK_STOPPED 0X0020 #define RTC_REG_1_UNUSED 0X0040 #define RTC_REG_1_EXT_CLK_MODE 0X0080 #define RTC_REG_2_MASK 0X0000 #define RTC_REG_3_MASK 0X0008 // RTC registers indices #define RTC_REG_1_INDEX 1 #define RTC_REG_2_INDEX 2 #define RTC_REG_3_INDEX 3 #define RTC_SECONDS_INDEX 4 #define RTC_MINUTES_INDEX 5 #define RTC_HOURS_INDEX 6 #define RTC_DAYS_INDEX 7 #define RTC_WEEKDAYS_INDEX 8 #define RTC_MONTHS_INDEX 9 #define RTC_YEARS_INDEX 10 // This command puts RTC into read mode from // address 0 #define RTC_READ_ALL 0x00A0 #define RTC_ACCURACY_TIMEOUT 1000 //ms #define RTC_ACCURACY_TIMEOUT_TOLERANCE 1050 //ms #define NUM_OF_ITEMS_TO_READ 11 typedef enum RTC_Self_Test_States { RTC_SELF_TEST_STATE_START = 0, RTC_SELF_TEST_STATE_CHECK_CTRL_REGS, RTC_SELF_TEST_STATE_COMPARE_SECONDS, RTC_SELF_TEST_STATE_CHECK_ACCURACY, RTC_SELF_TEST_STATE_COMPLETE } RTC_SELF_TEST_STATE_T; typedef enum RTC_Read_Data { RTC_SEND_COMMAND = 0, RTC_WAIT_FOR_TRANSFER_AND_READ, RTC_READ_COMPLETE } RTC_GET_DATA_STATE_T; typedef enum RTC_Exec_State { RTC_EXEC_STATE_WAIT_FOR_POST = 0, RTC_EXEC_STATE_WAIT_FOR_COUNTER, RTC_EXEC_STATE_READ } RTC_EXEC_STATE_T; static RTC_SELF_TEST_STATE_T RTCSelfTestState = RTC_SELF_TEST_STATE_START; static RTC_GET_DATA_STATE_T RTCGetDataState = RTC_SEND_COMMAND; static RTC_EXEC_STATE_T RTCExecState = RTC_EXEC_STATE_WAIT_FOR_POST; static U32 RTCSelfTestTimer = 0; static U32 RTCPreviousSecond = 0; static U32 timeCounter = 1; static BOOL hasWriteBeenRequested = FALSE; // TODO: Increase the size of the buffer static U16 rxBuffer[NUM_OF_ITEMS_TO_READ]; static U16 txBuffer[] = {RTC_READ_ALL, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; static struct RTCTimestamp { U08 seconds; U08 minutes; U08 hours; U08 days; U08 months; U08 years; } timestamp; void initRTC() { // Do nothing for now } // TODO: add the pointer to the buffers in the input arguments void getRTCData() { switch ( RTCGetDataState ) { case RTC_SEND_COMMAND: mibspiSetData(mibspiREG3, 0, txBuffer); mibspiTransfer(mibspiREG3, 0); RTCGetDataState = RTC_WAIT_FOR_TRANSFER_AND_READ; break; case RTC_WAIT_FOR_TRANSFER_AND_READ: if ( mibspiIsTransferComplete(mibspiREG3, 0) ) { mibspiGetData(mibspiREG3, 0, rxBuffer); RTCGetDataState = RTC_READ_COMPLETE; } break; case RTC_READ_COMPLETE: // Done with reading and transfer do nothing break; default: // TODO: Set an alarm or try multiple times (3 times) before failing break; } } // TODO: Does this function need to return a bool? BOOL setRTCTimestamp( U08 secs, U08 mins, U08 hours, U08 days, U08 months, U08 years ) { hasWriteBeenRequested = TRUE; U08 decimalSeconds = convertDecimal2BCD( secs ); U08 decimalMins = convertDecimal2BCD( mins ); U08 decimalHours = convertDecimal2BCD( hours ); U08 decimalDays = convertDecimal2BCD( days ); U08 decimalMonths = convertDecimal2BCD( months ); U08 decimalYears = convertDecimal2BCD( years ); timestamp.seconds = decimalSeconds; timestamp.minutes = decimalMins; timestamp.hours = decimalHours; timestamp.days = decimalDays; timestamp.months = decimalMonths; timestamp.years = decimalYears; } BOOL isRTCFunctional() { BOOL hasTestPassed = TRUE; U16 controlReg1 = rxBuffer[RTC_REG_1_INDEX]; U16 controlReg2 = rxBuffer[RTC_REG_2_INDEX]; U16 controlReg3 = rxBuffer[RTC_REG_2_INDEX]; if ( ! controlReg1 & RTC_REG_1_12_HOUR_MODE ) { // Set the alarm for 24 hour mode hasTestPassed = FALSE; } if ( ! controlReg1 & RTC_REG_1_PORO ) { // Set the alarm for PORO low mode hasTestPassed = FALSE; } if ( ! controlReg1 & RTC_REG_1_CLK_STOPPED ) { // Set the alarm for clock stopped mode hasTestPassed = FALSE; } if ( ! controlReg1 & RTC_REG_1_UNUSED ) { // Set the alarm for unused bit set to 1 mode hasTestPassed = FALSE; } if ( ! controlReg1 & RTC_REG_1_EXT_CLK_MODE ) { // Set the alarm for clock set on external mode hasTestPassed = FALSE; } if ( ! controlReg2 & RTC_REG_2_MASK ) { // Set the alarm for register 2 hasTestPassed = FALSE; } if ( ! controlReg3 & RTC_REG_3_MASK ) { // Set the alarm for register 3 hasTestPassed = FALSE; } return hasTestPassed; } SELF_TEST_STATUS_T execRTCSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; switch ( RTCSelfTestState ) { case RTC_SELF_TEST_STATE_START: getRTCData(); RTCSelfTestState = RTC_SELF_TEST_STATE_CHECK_CTRL_REGS; break; case RTC_SELF_TEST_STATE_CHECK_CTRL_REGS: getRTCData(); if ( RTCGetDataState == RTC_READ_COMPLETE ) { // Reset the states RTCGetDataState = RTC_SEND_COMMAND; if ( isRTCFunctional() ) { RTCSelfTestState = RTC_SELF_TEST_STATE_COMPARE_SECONDS; } else { result = SELF_TEST_STATUS_FAILED; RTCSelfTestState = RTC_SELF_TEST_STATE_COMPLETE; } } break; case RTC_SELF_TEST_STATE_COMPARE_SECONDS: getRTCData(); if ( RTCGetDataState == RTC_READ_COMPLETE ) { // Reset the states RTCGetDataState = RTC_SEND_COMMAND; U32 RTCCurrentSecond = rxBuffer[RTC_SECONDS_INDEX]; if ( RTCPreviousSecond == 0 ) { RTCPreviousSecond = RTCCurrentSecond; } else if ( RTCCurrentSecond > RTCPreviousSecond ) { RTCSelfTestTimer = getMSTimerCount(); RTCSelfTestState = RTC_SELF_TEST_STATE_CHECK_ACCURACY; } } break; case RTC_SELF_TEST_STATE_CHECK_ACCURACY: if ( didTimeout( RTCSelfTestTimer, RTC_ACCURACY_TIMEOUT ) ) { U32 elapsedTime = calcTimeSince(RTCSelfTestTimer); if ( elapsedTime > RTC_ACCURACY_TIMEOUT_TOLERANCE ) { result = SELF_TEST_STATUS_FAILED; } else { result = SELF_TEST_STATUS_PASSED; } RTCSelfTestState = RTC_SELF_TEST_STATE_COMPLETE; } break; case RTC_SELF_TEST_STATE_COMPLETE: break; default: // TODO: Add the alarms result = SELF_TEST_STATUS_FAILED; break; } return result; } U08 convertBCD2Decimal( U08 bcd ) { U08 bcdHigh; U08 bcdLow; U08 decimal; bcdHigh = ( bcd & 0xF0 ) >> 4; bcdLow = ( bcd & 0x0F ); decimal = ( bcdHigh * 10 ) + bcdLow; return decimal; } U08 convertDecimal2BCD( U08 decimal ) { U08 decimalHigh; U08 decimalLow; U08 bcd; // Assuming all the decimal provided // are maximum 2 digits decimalHigh = decimal / 10; decimalLow = decimal % 10; bcd = (decimalHigh << 4) + decimalLow; return bcd; } void execRTC() { switch ( RTCExecState ) { case RTC_EXEC_STATE_WAIT_FOR_POST: if ( RTCSelfTestState == RTC_SELF_TEST_STATE_COMPLETE ) { RTCExecState = RTC_EXEC_STATE_WAIT_FOR_COUNTER; } break; case RTC_EXEC_STATE_WAIT_FOR_COUNTER: if ( hasWriteBeenRequested ) { } if ( timeCounter == 18 ) { // Reset the states RTCGetDataState = RTC_SEND_COMMAND; getRTCData(); RTCExecState = RTC_EXEC_STATE_READ; } else { timeCounter++; } break; case RTC_EXEC_STATE_READ: getRTCData(); if ( RTCGetDataState == RTC_READ_COMPLETE ) { U08 testDate = (U08)rxBuffer[RTC_SECONDS_INDEX]; convertBCD2Decimal( testDate ); timeCounter = 1; RTCExecState = RTC_EXEC_STATE_WAIT_FOR_COUNTER; } break; default: break; } }