/************************************************************************** * * 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 // For calculating epoch #include "Common.h" #include "Timers.h" #include "RTC.h" #include "mibspi.h" // TODO: ADD FUNCTION HEADERS // ********** Definitions ********** #define RTC_REG_1_12_HOUR_MODE 0X0004 // 12-hour or 24-hour mode #define RTC_REG_1_PORO 0X0008 // Power On Reset Override #define RTC_REG_1_CLK_STOPPED 0X0020 // RTC source clock #define RTC_REG_1_UNUSED 0X0040 // Unused #define RTC_REG_1_EXT_CLK_MODE 0X0080 // RTC external or normal mode #define RTC_REG_2_MASK 0X00FF #define RTC_REG_2_MSF 0X0080 // Minute or second interrupt #define RTC_REG_2_CDTF 0X0008 // Countdown timer interrupt #define RTC_REG_2_AF 0X0010 // Alarm interrupt #define RTC_REG_2_TSF2 0X0020 // Timestamp interrupt #define RTC_REG_3_MASK 0X00FF #define RTC_REG_3_BF 0x0008 // RTC registers indices #define RTC_REG_1_INDEX 1U #define RTC_REG_2_INDEX 2U #define RTC_REG_3_INDEX 3U #define RTC_SECONDS_INDEX 4U #define RTC_MINUTES_INDEX 5U #define RTC_HOURS_INDEX 6U #define RTC_DAYS_INDEX 7U #define RTC_WEEKDAYS_INDEX 8U #define RTC_MONTHS_INDEX 9U #define RTC_YEARS_INDEX 10U #define BUFFER_INDEX_0 0U #define BUFFER_INDEX_1 1U #define BUFFER_INDEX_2 2U #define BUFFER_INDEX_3 3U #define BUFFER_INDEX_4 4U // *************** MibSPI values ************* // #define MIBSPI_MAX_BUFFER_LENGTH 127U #define MIBSPI_CONTINUOUS_MODE 4U #define MIBSPI_CHIP_SELECT_ACTIVE 1U #define MIBSPI_CHIP_SELECT_DEACTIVE 0U #define MIBSPI_NO_WDELAY 0U #define MIBSPI_LOCK_TG 0U #define MIBSPI_DATA_FORMAT_ZERO 0U #define MIBSPI_GROUP_ZERO 0U #define MIBSPI_BUFFER_MODE_BIT_SHIFT 13U #define MIBSPI_CHIP_SELECT_BIT_SHIFT 12U #define MIBSPI_NO_WDELAY_BIT_SHIT 10U #define MIBSPI_LOCK_TRANS_BIT_SHIFT 11U #define MIBSPI_DATA_FORMAT_ZERO_BIT_SHIFT 8U #define MIBSPI_BUFFER_TRANS_BIT_SHIFT 8U // *************** RTC definitions ************* // #define RTC_RAM_PREP_BUFFER_LENGTH 3U #define RTC_TIMESTAMP_BUFFER_LENGTH 8U #define RTC_GENERAL_BUFFER_LENGTH 11U #define RTC_PREP_RAM_INDEX 0U #define RTC_RAM_HIGH_ADDRESS_INDEX 1U #define RTC_RAM_LOW_ADDRESS_INDEX 2U #define RTC_RAM_COMMAND_INDEX 3U #define RTC_RAM_HIGH_ADDRESS_BIT_SHIFT 8U #define RTC_READ_FROM_REG0 0x00A0 // RTC read from address 0 #define RTC_WRITE_TO_REG3 0x0023 // Seconds register #define RTC_PREP_RAM_READ_WRITE 0x003A // RTC cmd prior to RAM ops #define RTC_WRITE_TO_RAM 0x003C // RTC RAM write #define RTC_READ_FROM_RAM 0x00BD // RTC RAM read #define RTC_ACCURACY_TIMEOUT 1000U // ms #define RTC_ACCURACY_TIMEOUT_TOLERANCE 1050U // ms #define TIMER_COUNTER_TO_REQUEST_READ 18U #define MAX_ALLOWED_FAILED_RTC_TRANSFERS 3U #define MAX_ALLOWED_RTC_RAM_BYTES 100U #define MAX_ALLOWED_RTC_RAM_ADDRESS 512U typedef enum RTC_Self_Test_States { RTC_SELF_TEST_STATE_START = 0, RTC_SELF_TEST_STATE_CHECK_CTRL_REGS, RTC_SELF_TEST_STATE_WAIT_FOR_FIRST_SECOND, RTC_SELF_TEST_STATE_WAIT_FOR_SECOND_SECOND, 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_SERVICE_COMPLETE } RTC_GET_DATA_STATE_T; typedef enum RTC_Exec_State { RTC_EXEC_STATE_WAIT_FOR_POST = 0, RTC_EXEC_STATE_IDLE, RTC_EXEC_STATE_PREP_RAM, RTC_EXEC_STATE_WRITE_TO_RAM, RTC_EXEC_STATE_READ_FROM_RAM, RTC_EXEC_STATE_READ, RTC_EXEC_STATE_WRITE, RTC_EXEC_STATE_FAULT } RTC_EXEC_STATE_T; #pragma pack(push,4) typedef struct { U16 seconds; U16 minutes; U16 hours; U16 days; U16 weekdays; U16 months; U16 years; } RTC_TIMESTAMP_T; #pragma pack(pop) // ********** private data ********** static RTC_SELF_TEST_STATE_T RTCSelfTestState = RTC_SELF_TEST_STATE_START; static RTC_GET_DATA_STATE_T RTCServiceState = RTC_SEND_COMMAND; static RTC_EXEC_STATE_T RTCExecState = RTC_EXEC_STATE_WAIT_FOR_POST; static SELF_TEST_STATUS_T RTCSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; static RTC_RAM_STATUS_T RTCRAMStatus = RTC_RAM_STATUS_COMPLETE; static RTC_RAM_STATE_T RTCRAMState = RTC_RAM_STATE_READY; static RTC_TIMESTAMP_T RTCTimestampStruct; static U32 RTCSelfTestTimer = 0; static U32 RTCPreviousSecond = 0; static U32 RAMBufferLength = 0; static U32 lastEpochTime = 0; static U32 previousTransferLength = 0; static U32 timeCounter = 1; static U32 numberOfFailedRTCTransfers = 1; static BOOL hasWriteToRTCRequested = FALSE; static BOOL hasWriteToRAMRequested = FALSE; static BOOL hasReadFromRAMRequested = FALSE; static BOOL hasServiceRTCRequested = FALSE; static U16 rxBuffer[ MIBSPI_MAX_BUFFER_LENGTH + 1 ]; static U16 txBuffer[ MIBSPI_MAX_BUFFER_LENGTH + 1 ]; static U16 RAMBuffer[ MIBSPI_MAX_BUFFER_LENGTH ]; // ********** Private function prototypes ********* static BOOL serviceRTC( U16* bufferTransmit, U16* bufferReceive, U16 bufferLength ); static BOOL isRTCFunctional(); static U08 convertBCD2Decimal( U08 bcd ); static U08 convertDecimal2BCD( U08 decimal ); static U32 convertTime2Epoch(); static void updateReadTimestampStruct(); static BOOL setMibSPIBufferLength( U16 length ); static void prepBufferForReadCommand( U16 length ); // Puts the read command static RTC_SELF_TEST_STATE_T handleSelfTestStart(); static RTC_SELF_TEST_STATE_T handleSelfTestCheckCtrlRegs(); static RTC_SELF_TEST_STATE_T handleSelfTestWaitForFirstSecond(); static RTC_SELF_TEST_STATE_T handleSelfTestWaitForSecondSecond(); static RTC_SELF_TEST_STATE_T handleSelfTestCheckAccuracy(); static RTC_EXEC_STATE_T handleExecWaitForPostState(); static RTC_EXEC_STATE_T handleExecIdleState(); static RTC_EXEC_STATE_T handleExecReadState(); static RTC_EXEC_STATE_T handleExecPrepRAMState(); static RTC_EXEC_STATE_T handleExecWriteToRAMState(); static RTC_EXEC_STATE_T handleExecReadFromRAMState(); static RTC_EXEC_STATE_T handleExecWriteState(); // ********** Public functions ********** /************************************************************************* * @brief initRTC * The initRTC initializes the RTC * @details * Inputs : none * Outputs : The function is empty for now * @param none * @return none *************************************************************************/ void initRTC() { // Do nothing for now } /************************************************************************* * @brief setRTCTimestamp * The setRTCTimestamp gets the timestamp values, converts them into BCD * and inserts them into the txBuffer to be written into the RTC * @details * Inputs : seconds, minutes, hours, days, months, years * Outputs : txBuffer will be prepared with the timestamp * @param none * @return none *************************************************************************/ void setRTCTimestamp( U08 secs, U08 mins, U08 hours, U08 days, U08 months, U16 years ) { hasWriteToRTCRequested = TRUE; U16 decimalSeconds = convertDecimal2BCD( secs ); U16 decimalMins = convertDecimal2BCD( mins ); U16 decimalHours = convertDecimal2BCD( hours ); U16 decimalDays = convertDecimal2BCD( days ); U16 decimalMonths = convertDecimal2BCD( months ); U16 decimalYears = convertDecimal2BCD( years - 2000 ); txBuffer[0] = RTC_WRITE_TO_REG3; txBuffer[1] = convertDecimal2BCD( secs ); txBuffer[2] = convertDecimal2BCD( mins ); txBuffer[3] = convertDecimal2BCD( hours ); txBuffer[4] = convertDecimal2BCD( days ); txBuffer[5] = 0; txBuffer[6] = convertDecimal2BCD( months ); txBuffer[7] = convertDecimal2BCD( years - 2000 ); } /************************************************************************* * @brief execRTCSelfTest * The execRTCSelfTest runs the RTC POST during the self test * @details * Inputs : none * Outputs : SELF_TEST_STATUS_T * @param none * @return SELF_TEST_STATUS_T *************************************************************************/ SELF_TEST_STATUS_T execRTCSelfTest() { switch ( RTCSelfTestState ) { case RTC_SELF_TEST_STATE_START: RTCSelfTestState = handleSelfTestStart(); break; case RTC_SELF_TEST_STATE_CHECK_CTRL_REGS: RTCSelfTestState = handleSelfTestCheckCtrlRegs(); break; case RTC_SELF_TEST_STATE_WAIT_FOR_FIRST_SECOND: RTCSelfTestState = handleSelfTestWaitForFirstSecond(); break; case RTC_SELF_TEST_STATE_WAIT_FOR_SECOND_SECOND: RTCSelfTestState = handleSelfTestWaitForSecondSecond(); break; case RTC_SELF_TEST_STATE_CHECK_ACCURACY: RTCSelfTestState = handleSelfTestCheckAccuracy(); break; case RTC_SELF_TEST_STATE_COMPLETE: // Done with the state // TODO: If POST failed, set the proper alarm break; default: // TODO: Add the alarms RTCSelfTestResult = SELF_TEST_STATUS_FAILED; break; } return RTCSelfTestResult; } /************************************************************************* * @brief execRTC * The execRTC runs the RTC during normal operations * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ void execRTC() { switch ( RTCExecState ) { case RTC_EXEC_STATE_WAIT_FOR_POST: RTCExecState = handleExecWaitForPostState(); break; case RTC_EXEC_STATE_IDLE: RTCExecState = handleExecIdleState(); break; case RTC_EXEC_STATE_PREP_RAM: RTCExecState = handleExecPrepRAMState(); break; case RTC_EXEC_STATE_WRITE_TO_RAM: RTCExecState = handleExecWriteToRAMState(); break; case RTC_EXEC_STATE_READ_FROM_RAM: RTCExecState = handleExecReadFromRAMState(); break; case RTC_EXEC_STATE_WRITE: RTCExecState = handleExecWriteState(); break; case RTC_EXEC_STATE_READ: RTCExecState = handleExecReadState(); break; case RTC_EXEC_STATE_FAULT: // Something failed set the alarms // TODO: set the alarms and stuff break; default: break; } } // TODO: Make this a const U32 getRTCTimestamp() { return lastEpochTime; } RTC_RAM_STATUS_T writeToRAM( U16 address, U16* data, U32 length ) { RTC_RAM_STATUS_T status = RTCRAMStatus; if ( status == RTC_RAM_STATUS_IDLE ) { if ( address > MAX_ALLOWED_RTC_RAM_ADDRESS ) { status = RTC_RAM_STATUS_ILLEGAL_ADDRESS; } else if ( length > MAX_ALLOWED_RTC_RAM_BYTES ) { status = RTC_RAM_STATUS_BYTES_EXCEEDED; } else { RTCRAMStatus = status = RTC_RAM_STATUS_IN_PROGRESS; RTCRAMState = RTC_RAM_STATE_BUSY; hasWriteToRAMRequested = TRUE; RAMBufferLength = length; txBuffer[ RTC_PREP_RAM_INDEX ] = RTC_PREP_RAM_READ_WRITE; txBuffer[ RTC_RAM_HIGH_ADDRESS_INDEX ] = ( address >> RTC_RAM_HIGH_ADDRESS_BIT_SHIFT ); txBuffer[ RTC_RAM_LOW_ADDRESS_INDEX ] = ( address & 0x00FF ); txBuffer[ RTC_RAM_COMMAND_INDEX ] = RTC_WRITE_TO_RAM; U08 i; for ( i = 0; i < RAMBufferLength; i++ ) { // The first 3 elements in txBuffer are filled txBuffer[ i + BUFFER_INDEX_4 ] = data[ i ]; } } } return status; } RTC_RAM_STATUS_T readFromRAM( U16 address, U32 length ) { RTC_RAM_STATUS_T status = RTCRAMStatus; if ( status == RTC_RAM_STATUS_IDLE ) { if ( address > MAX_ALLOWED_RTC_RAM_ADDRESS ) { status = RTC_RAM_STATUS_ILLEGAL_ADDRESS; } else if ( length > MAX_ALLOWED_RTC_RAM_BYTES ) { status = RTC_RAM_STATUS_BYTES_EXCEEDED; } else { status = RTCRAMStatus = RTC_RAM_STATUS_IN_PROGRESS; hasReadFromRAMRequested = TRUE; RAMBufferLength = length; txBuffer[ RTC_PREP_RAM_INDEX ] = RTC_PREP_RAM_READ_WRITE; txBuffer[ RTC_RAM_HIGH_ADDRESS_INDEX ] = ( address >> RTC_RAM_HIGH_ADDRESS_BIT_SHIFT ); txBuffer[ RTC_RAM_LOW_ADDRESS_INDEX ] = ( address & 0x00FF ); txBuffer[ RTC_RAM_COMMAND_INDEX ] = RTC_READ_FROM_RAM; U08 i; for ( i = 0; i < length; i++ ) { txBuffer[ i + BUFFER_INDEX_4 ] = 0x0000; } } } else if ( status == RTC_RAM_STATUS_COMPLETE ) { RTCRAMStatus = RTC_RAM_STATUS_IDLE; } return status; } RTC_RAM_STATE_T getRTCRAMState() { RTC_RAM_STATE_T state = RTC_RAM_STATE_READY; return RTCRAMState; } // TODO: make this function a const RTC_RAM_STATUS_T getRTCRAMStatus() { return RTCRAMStatus; } void getDataFromRAM( U16* externalBuffer, U32 length ) { U08 i; for ( i = 0; i < length; i++ ) { externalBuffer[ i ] = RAMBuffer[ i + 1 ]; } } // ********** Private functions ********* static BOOL serviceRTC( U16* bufferTransmit, U16* bufferReceive, U16 bufferLength ) { BOOL result = FALSE; BOOL bufferStatus = FALSE; if ( !hasServiceRTCRequested ) { RTCServiceState = RTC_SEND_COMMAND; hasServiceRTCRequested = TRUE; } switch ( RTCServiceState ) { case RTC_SEND_COMMAND: if ( previousTransferLength == bufferLength ) { bufferStatus = TRUE; } else if ( setMibSPIBufferLength( bufferLength ) ) { bufferStatus = TRUE; } if ( bufferStatus ) { mibspiSetData( mibspiREG3, MIBSPI_GROUP_ZERO, bufferTransmit ); mibspiTransfer( mibspiREG3, MIBSPI_GROUP_ZERO ); numberOfFailedRTCTransfers = 1; previousTransferLength = bufferLength; RTCServiceState = RTC_WAIT_FOR_TRANSFER_AND_READ; } else { RTCServiceState = RTC_SERVICE_COMPLETE; } break; case RTC_WAIT_FOR_TRANSFER_AND_READ: if ( mibspiIsTransferComplete( mibspiREG3, MIBSPI_GROUP_ZERO ) ) { mibspiGetData( mibspiREG3, MIBSPI_GROUP_ZERO, bufferReceive ); RTCServiceState = RTC_SERVICE_COMPLETE; result = TRUE; } else if ( numberOfFailedRTCTransfers >= MAX_ALLOWED_FAILED_RTC_TRANSFERS ) { RTCServiceState = RTC_SERVICE_COMPLETE; } else { // Transfer to RTC failed. This transfer // should be done in 50ms numberOfFailedRTCTransfers++; } hasServiceRTCRequested = FALSE; break; case RTC_SERVICE_COMPLETE: // Done with reading and transfer break; default: // We should never get here break; } return result; } static BOOL isRTCFunctional() { BOOL hasTestPassed = TRUE; U16 controlReg1 = rxBuffer[RTC_REG_1_INDEX]; U16 controlReg2 = rxBuffer[RTC_REG_2_INDEX]; U16 controlReg3 = rxBuffer[RTC_REG_3_INDEX]; // Ignore the clear flags controlReg2 = controlReg2 & ~RTC_REG_2_MSF; controlReg2 = controlReg2 & ~RTC_REG_2_CDTF; controlReg2 = controlReg2 & ~RTC_REG_2_AF; controlReg2 = controlReg2 & ~RTC_REG_2_TSF2; controlReg3 = controlReg3 & ~RTC_REG_3_BF; 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; } static U08 convertBCD2Decimal( U08 bcd ) { U08 bcdHigh; U08 bcdLow; U08 decimal; bcdHigh = ( bcd & 0xF0 ) >> 4; bcdLow = ( bcd & 0x0F ); decimal = ( bcdHigh * 10 ) + bcdLow; return decimal; } static 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; } static U32 convertTime2Epoch() { struct tm t; time_t epochTime; t.tm_sec = RTCTimestampStruct.seconds; t.tm_min = RTCTimestampStruct.minutes; t.tm_hour = RTCTimestampStruct.hours; t.tm_mday = RTCTimestampStruct.days; t.tm_mon = RTCTimestampStruct.months - 1; t.tm_year = RTCTimestampStruct.years + 2000 - 1970; epochTime = mktime(&t); return (U32)epochTime; } static void updateReadTimestampStruct() { U16 decimalSeconds = convertBCD2Decimal( rxBuffer[ RTC_SECONDS_INDEX ] ); U16 decimalMins = convertBCD2Decimal( rxBuffer[ RTC_MINUTES_INDEX ] ); U16 decimalHours = convertBCD2Decimal( rxBuffer[ RTC_HOURS_INDEX ] ); U16 decimalDays = convertBCD2Decimal( rxBuffer[ RTC_DAYS_INDEX ] ); U16 decimalMonths = convertBCD2Decimal( rxBuffer[ RTC_MONTHS_INDEX ] ); U16 decimalYears = convertBCD2Decimal( rxBuffer[ RTC_YEARS_INDEX ] ); RTCTimestampStruct.seconds = decimalSeconds; RTCTimestampStruct.minutes = decimalMins; RTCTimestampStruct.hours = decimalHours; RTCTimestampStruct.days = decimalDays; RTCTimestampStruct.weekdays = 0; // Weekdays will not be used RTCTimestampStruct.months = decimalMonths; RTCTimestampStruct.years = decimalYears; } static BOOL setMibSPIBufferLength( U16 length ) { BOOL transferStatus = FALSE; // The max allowed buffer length in the // MibSPI RAM is 127 if ( length <= MIBSPI_MAX_BUFFER_LENGTH ) { U32 i = 0; mibspiREG3->TGCTRL[0U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[1U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[1U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[2U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[2U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[3U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[3U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[4U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[4U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[5U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[5U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[6U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[6U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[7U] &= ~(uint32)( (uint32)MIBSPI_MAX_BUFFER_LENGTH << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[7U] |= (uint32)( (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); mibspiREG3->TGCTRL[8U] = (uint32)length << MIBSPI_BUFFER_TRANS_BIT_SHIFT; mibspiREG3->LTGPEND = ( mibspiREG3->LTGPEND & 0xFFFF00FFU ) | (uint32)( ((uint32)length - 1U) << MIBSPI_BUFFER_TRANS_BIT_SHIFT ); while ( i < ( length - 1U ) ) { mibspiRAM3->tx[i].control = (uint16)( (uint16)MIBSPI_CONTINUOUS_MODE << MIBSPI_BUFFER_MODE_BIT_SHIFT ) /* buffer mode */ | (uint16)( (uint16)MIBSPI_CHIP_SELECT_ACTIVE << MIBSPI_CHIP_SELECT_BIT_SHIFT ) /* chip select hold */ | (uint16)( (uint16)MIBSPI_NO_WDELAY << MIBSPI_NO_WDELAY_BIT_SHIT ) /* enable WDELAY */ | (uint16)( (uint16)MIBSPI_LOCK_TG << MIBSPI_LOCK_TRANS_BIT_SHIFT ) /* lock transmission */ | (uint16)( (uint16)MIBSPI_DATA_FORMAT_ZERO << MIBSPI_DATA_FORMAT_ZERO_BIT_SHIFT ) /* data format */ /*SAFETYMCUSW 334 S MR:10.5 "LDRA Tool issue" */ | ((uint16)( ~((uint16)0xFFU ^ (uint16)CS_0)) & (uint16)0x00FFU ); /* chip select */ i++; } mibspiRAM3->tx[i].control = (uint16)( (uint16)MIBSPI_CONTINUOUS_MODE << MIBSPI_BUFFER_MODE_BIT_SHIFT ) /* buffer mode */ | (uint16)( (uint16)MIBSPI_CHIP_SELECT_DEACTIVE << MIBSPI_CHIP_SELECT_BIT_SHIFT ) /* chip select hold */ | (uint16)( (uint16)MIBSPI_NO_WDELAY << MIBSPI_NO_WDELAY_BIT_SHIT ) /* enable WDELAY */ | (uint16)( (uint16)MIBSPI_DATA_FORMAT_ZERO << MIBSPI_DATA_FORMAT_ZERO_BIT_SHIFT ) /* data format */ /*SAFETYMCUSW 334 S MR:10.5 "LDRA Tool issue" */ | ((uint16)( ~((uint16)0xFFU ^ (uint16)CS_0)) & (uint16)0x00FFU ); /* chip select */ transferStatus = TRUE; } else { transferStatus = FALSE; } return transferStatus; } static void prepBufferForReadCommand( U16 length ) { txBuffer[ BUFFER_INDEX_0 ] = RTC_READ_FROM_REG0; U08 i; for ( i = 1; i < length; i++ ) { txBuffer[ i ] = 0x0000; } } static RTC_EXEC_STATE_T handleExecWaitForPostState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_WAIT_FOR_POST; if ( RTCSelfTestState == RTC_SELF_TEST_STATE_COMPLETE && RTCSelfTestResult == SELF_TEST_STATUS_PASSED ) { result = RTC_EXEC_STATE_IDLE; } else if ( RTCSelfTestState == RTC_SELF_TEST_STATE_COMPLETE && RTCSelfTestResult == SELF_TEST_STATUS_FAILED ) { result = RTC_EXEC_STATE_FAULT; } return result; } static RTC_EXEC_STATE_T handleExecIdleState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_IDLE; if ( hasWriteToRTCRequested ) { result = RTC_EXEC_STATE_WRITE; } else if ( hasWriteToRAMRequested ) { result = RTC_EXEC_STATE_PREP_RAM; } else if ( hasReadFromRAMRequested ) { result = RTC_EXEC_STATE_PREP_RAM; } else if ( timeCounter == TIMER_COUNTER_TO_REQUEST_READ ) { prepBufferForReadCommand( RTC_GENERAL_BUFFER_LENGTH ); result = RTC_EXEC_STATE_READ; } else { timeCounter++; } return result; } static RTC_EXEC_STATE_T handleExecWriteState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_WRITE; if ( setMibSPIBufferLength( RTC_TIMESTAMP_BUFFER_LENGTH ) ) { BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_0 ], &rxBuffer[ BUFFER_INDEX_0 ], RTC_TIMESTAMP_BUFFER_LENGTH ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { // Reset the counter timeCounter = 1; hasWriteToRTCRequested = FALSE; // Reset the RTC Service commands RTCServiceState = RTC_SEND_COMMAND; result = RTC_EXEC_STATE_IDLE; } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && ! isStatusOk ) { result = RTC_EXEC_STATE_FAULT; } } else { result = RTC_EXEC_STATE_FAULT; } return result; } static RTC_EXEC_STATE_T handleExecPrepRAMState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_PREP_RAM; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_0 ], &RAMBuffer[ BUFFER_INDEX_0 ], RTC_RAM_PREP_BUFFER_LENGTH ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { if ( hasWriteToRAMRequested ) { result = RTC_EXEC_STATE_WRITE_TO_RAM; } else if ( hasReadFromRAMRequested ) { result = RTC_EXEC_STATE_READ_FROM_RAM; } } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { result = RTC_EXEC_STATE_FAULT; } return result; } static RTC_EXEC_STATE_T handleExecWriteToRAMState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_WRITE_TO_RAM; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_3 ], &RAMBuffer[ BUFFER_INDEX_0 ], RAMBufferLength + 1 ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { result = RTC_EXEC_STATE_IDLE; RTCRAMStatus = RTC_RAM_STATUS_COMPLETE; hasWriteToRAMRequested = FALSE; } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { result = RTC_EXEC_STATE_FAULT; RTCRAMStatus = RTC_RAM_STATUS_FAILED; hasWriteToRAMRequested = FALSE; } return result; } static RTC_EXEC_STATE_T handleExecReadFromRAMState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_READ_FROM_RAM; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_3 ], &RAMBuffer[ BUFFER_INDEX_0 ], RAMBufferLength + 1 ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { result = RTC_EXEC_STATE_IDLE; hasReadFromRAMRequested = FALSE; } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { result = RTC_EXEC_STATE_FAULT; } return result; } static RTC_EXEC_STATE_T handleExecReadState() { RTC_EXEC_STATE_T result = RTC_EXEC_STATE_READ; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_0 ], &rxBuffer[ BUFFER_INDEX_0 ], RTC_GENERAL_BUFFER_LENGTH ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { if ( isRTCFunctional() ) { updateReadTimestampStruct(); lastEpochTime = convertTime2Epoch(); timeCounter = 1; result = RTC_EXEC_STATE_IDLE; } else { result = RTC_EXEC_STATE_FAULT; } } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { result = RTC_EXEC_STATE_FAULT; } return result; } // Private self test functions static RTC_SELF_TEST_STATE_T handleSelfTestStart() { RTC_SELF_TEST_STATE_T result = RTC_SELF_TEST_STATE_START; prepBufferForReadCommand( RTC_GENERAL_BUFFER_LENGTH ); result = RTC_SELF_TEST_STATE_CHECK_CTRL_REGS; return result; } static RTC_SELF_TEST_STATE_T handleSelfTestCheckCtrlRegs() { RTC_SELF_TEST_STATE_T result = RTC_SELF_TEST_STATE_CHECK_CTRL_REGS; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_0 ], &rxBuffer[ BUFFER_INDEX_0 ], RTC_GENERAL_BUFFER_LENGTH ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { if ( isRTCFunctional() ) { U32 RTCCurrentSecond = rxBuffer[ RTC_SECONDS_INDEX ]; RTCPreviousSecond = RTCCurrentSecond; result = RTC_SELF_TEST_STATE_WAIT_FOR_FIRST_SECOND; } else { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; result = RTC_SELF_TEST_STATE_COMPLETE; } } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; result = RTC_SELF_TEST_STATE_COMPLETE; } return result; } static RTC_SELF_TEST_STATE_T handleSelfTestWaitForFirstSecond() { RTC_SELF_TEST_STATE_T result = RTC_SELF_TEST_STATE_WAIT_FOR_FIRST_SECOND; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_0 ], &rxBuffer[ BUFFER_INDEX_0 ], RTC_GENERAL_BUFFER_LENGTH ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { if ( isRTCFunctional() ) { U32 RTCCurrentSecond = rxBuffer[ RTC_SECONDS_INDEX ]; if ( RTCCurrentSecond != RTCPreviousSecond ) { RTCPreviousSecond = RTCCurrentSecond; RTCSelfTestTimer = getMSTimerCount(); result = RTC_SELF_TEST_STATE_WAIT_FOR_SECOND_SECOND; } } else { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; result = RTC_SELF_TEST_STATE_COMPLETE; } } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; result = RTC_SELF_TEST_STATE_COMPLETE; } return result; } static RTC_SELF_TEST_STATE_T handleSelfTestWaitForSecondSecond() { RTC_SELF_TEST_STATE_T result = RTC_SELF_TEST_STATE_WAIT_FOR_SECOND_SECOND; BOOL isStatusOk = serviceRTC( &txBuffer[ BUFFER_INDEX_0 ], &rxBuffer[ BUFFER_INDEX_0 ], RTC_GENERAL_BUFFER_LENGTH ); if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { if ( isRTCFunctional() ) { U32 RTCCurrentSecond = rxBuffer[ RTC_SECONDS_INDEX ]; if ( RTCCurrentSecond != RTCPreviousSecond ) { result = RTC_SELF_TEST_STATE_CHECK_ACCURACY; } } else { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; result = RTC_SELF_TEST_STATE_COMPLETE; } } else if ( RTCServiceState == RTC_SERVICE_COMPLETE && !isStatusOk ) { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; result = RTC_SELF_TEST_STATE_COMPLETE; } return result; } static RTC_SELF_TEST_STATE_T handleSelfTestCheckAccuracy() { RTC_SELF_TEST_STATE_T result = RTC_SELF_TEST_STATE_CHECK_ACCURACY; if ( didTimeout( RTCSelfTestTimer, RTC_ACCURACY_TIMEOUT ) ) { U32 elapsedTime = calcTimeSince( RTCSelfTestTimer ); if ( elapsedTime > RTC_ACCURACY_TIMEOUT_TOLERANCE ) { RTCSelfTestResult = SELF_TEST_STATUS_FAILED; } else { RTCSelfTestResult = SELF_TEST_STATUS_PASSED; } result = RTC_SELF_TEST_STATE_COMPLETE; } return result; }