text: #include "rtcc.h"
  
  static void RTCC_Lock(void);
  static bool rtccTimeInitialized;
  static bool RTCCTimeInitialized(void);
  static uint8_t ConvertHexToBCD(uint8_t hexvalue);
  static uint8_t ConvertBCDToHex(uint8_t bcdvalue);
  
  void RTCC_Initialize(void)
  {
  
     RTCCON1Lbits.RTCEN = 0;
     
     __builtin_write_RTCC_WRLOCK();
     
     
     if(!RTCCTimeInitialized())
     {
         // set 2021-11-29 09-58-01
         DATEH = 0x2111;    // Year/Month
         DATEL = 0x2901;    // Date/Wday
         TIMEH = 0x958;    // hours/minutes
         TIMEL = 0x100;    // seconds
     }
  
     // PWCPS 1:1; PS 1:64; CLKSEL FOSC/2; FDIV 0; 
     RTCCON2L = 0x23;
     // DIV 31249; 
     RTCCON2H = 0x7A11;
     // PWCSTAB 0; PWCSAMP 0; 
     RTCCON3L = 0x00;
  
     // RTCEN enabled; OUTSEL TimerStamp A; PWCPOE disabled; PWCEN disabled; WRLOCK disabled; PWCPOL disabled; TSAEN disabled; RTCOE enabled; 
     RTCCON1L = 0x80C0; 
     
     // Enable RTCC, clear RTCWREN 
     RTCCON1Lbits.RTCEN = 1; 
     RTCC_Lock();
  
  }
  
  static void RTCC_Lock(void)
  {
      asm volatile("DISI #6");
      asm volatile("MOV #NVMKEY, W1");
      asm volatile("MOV #0x55, W2");
      asm volatile("MOV W2, [W1]");
      asm volatile("MOV #0xAA, W3");
      asm volatile("MOV W3, [W1]");
      asm volatile("BSET RTCCON1L, #11");
  }
  
  bool RTCC_TimeGet(struct tm *currentTime)
  {
      uint16_t register_value;
      if(RTCSTATLbits.SYNC)
      {
          return false;
      }
   
      register_value = DATEH;
      currentTime->tm_year = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      currentTime->tm_mon = ConvertBCDToHex(register_value & 0x00FF);
      
      register_value = DATEL;
      currentTime->tm_mday = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      currentTime->tm_wday = ConvertBCDToHex(register_value & 0x00FF);
      
      register_value = TIMEH;
      currentTime->tm_hour = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      currentTime->tm_min = ConvertBCDToHex(register_value & 0x00FF);
      
      register_value = TIMEL;
      currentTime->tm_sec = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      
      return true;
  }
  
  void RTCC_TimeSet(struct tm *initialTime)
  {
  
    __builtin_write_RTCC_WRLOCK();
  
     RTCCON1Lbits.RTCEN = 0;
     
  
     // set RTCC initial time
     DATEH = (ConvertHexToBCD(initialTime->tm_year) << 8) | ConvertHexToBCD(initialTime->tm_mon) ;  // YEAR/MONTH-1
     DATEL = (ConvertHexToBCD(initialTime->tm_mday) << 8) | ConvertHexToBCD(initialTime->tm_wday) ;  // /DAY-1/WEEKDAY
     TIMEH = (ConvertHexToBCD(initialTime->tm_hour) << 8)  | ConvertHexToBCD(initialTime->tm_min); // /HOURS/MINUTES
     TIMEL = (ConvertHexToBCD(initialTime->tm_sec) << 8) ;   // SECOND
             
     // Enable RTCC, clear RTCWREN         
     RTCCON1Lbits.RTCEN = 1;  
     RTCC_Lock();
  
  }
  
  bool RTCC_BCDTimeGet(bcdTime_t *currentTime)
  {
      uint16_t register_value;
      if(RTCSTATLbits.SYNC)
      {
          return false;
      }
  
      register_value = DATEH;
      currentTime->tm_year = (register_value & 0xFF00) >> 8;
      currentTime->tm_mon = register_value & 0x00FF;
      
      register_value = DATEL;
      currentTime->tm_mday = (register_value & 0xFF00) >> 8;
      currentTime->tm_wday = register_value & 0x00FF;
      
      register_value = TIMEH;
      currentTime->tm_hour = (register_value & 0xFF00) >> 8;
      currentTime->tm_min = register_value & 0x00FF;
     
      register_value = TIMEL;
      currentTime->tm_sec = (register_value & 0xFF00) >> 8;
  
      return true;
  }
  
  void RTCC_BCDTimeSet(bcdTime_t *initialTime)
  {
  
     __builtin_write_RTCC_WRLOCK();
  
     RTCCON1Lbits.RTCEN = 0;
     
  
     // set RTCC initial time
     DATEH = (initialTime->tm_year << 8) | (initialTime->tm_mon) ;  // YEAR/MONTH-1
     DATEL = (initialTime->tm_mday << 8) | (initialTime->tm_wday) ;  // /DAY-1/WEEKDAY
     TIMEH = (initialTime->tm_hour << 8) | (initialTime->tm_min); // /HOURS/MINUTES
     TIMEL = (initialTime->tm_sec << 8);   // SECONDS   
             
     // Enable RTCC, clear RTCWREN         
     RTCCON1Lbits.RTCEN = 1;  
     RTCC_Lock();
  
  }
  
  /**
   This function implements RTCC_TimeReset.This function is used to
   used by application to reset the RTCC value and reinitialize RTCC value.
  */
  void RTCC_TimeReset(bool reset)
  {
      rtccTimeInitialized = reset;
  }
  
  static bool RTCCTimeInitialized(void)
  {
      return(rtccTimeInitialized);
  }
  
  void RTCC_TimestampAEventManualSet(void)
  {
      RTCSTATLbits.TSAEVT = 1;
  }
  
  bool RTCC_TimestampADataGet(struct tm *currentTime)
  {
      uint16_t register_value;
      if(!RTCSTATLbits.TSAEVT)
      {
          return false;
      }
    
      register_value = TSADATEH;
      currentTime->tm_year = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      currentTime->tm_mon = ConvertBCDToHex(register_value & 0x00FF);
      
      register_value = TSADATEL;
      currentTime->tm_mday = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      currentTime->tm_wday = ConvertBCDToHex(register_value & 0x00FF);
      
      register_value = TSATIMEH;
      currentTime->tm_hour = ConvertBCDToHex((register_value & 0xFF00) >> 8);
      currentTime->tm_min = ConvertBCDToHex(register_value & 0x00FF);
      
      register_value = TSATIMEL;
      currentTime->tm_sec = ConvertBCDToHex((register_value & 0xFF00) >> 8);
     
      RTCSTATLbits.TSAEVT = 0;
  
      return true;
  }
  
  
  
  bool RTCC_TimestampA_BCDDataGet(bcdTime_t *currentTime)
  {
      uint16_t register_value;
      if(!RTCSTATLbits.TSAEVT)
      {
          return false;
      }
    
      register_value = TSADATEH;
      currentTime->tm_year = (register_value & 0xFF00) >> 8;
      currentTime->tm_mon = (register_value & 0x00FF);
      
      register_value = TSADATEL;
      currentTime->tm_mday = (register_value & 0xFF00) >> 8;
      currentTime->tm_wday = (register_value & 0x00FF);
      
      register_value = TSATIMEH;
      currentTime->tm_hour = (register_value & 0xFF00) >> 8;
      currentTime->tm_min = (register_value & 0x00FF);
      
      register_value = TSATIMEL;
      currentTime->tm_sec = (register_value & 0xFF00) >> 8;
     
      RTCSTATLbits.TSAEVT = 0;
  
      return true;
  }
  
  
  static uint8_t ConvertHexToBCD(uint8_t hexvalue)
  {
      uint8_t bcdvalue;
      bcdvalue = (hexvalue / 10) << 4;
      bcdvalue = bcdvalue | (hexvalue % 10);
      return (bcdvalue);
  }
  
  static uint8_t ConvertBCDToHex(uint8_t bcdvalue)
  {
      uint8_t hexvalue;
      hexvalue = (((bcdvalue & 0xF0) >> 4)* 10) + (bcdvalue & 0x0F);
      return hexvalue;
  }
  
  void __attribute__ ((weak)) RTCC_CallBack(void)
  {
      // Add your custom callback code here
  }
  
  /* Function:
      bool RTCC_Task(void)
  
    Summary:
      Status function which returns the RTCC interrupt flag status
  
    Description:
      This is the status function for the RTCC peripheral. 
  */
  bool RTCC_Task(void)
  {
      bool status;
      status = IFS3bits.RTCIF;
      if( IFS3bits.RTCIF)
      {
  		// RTCC callback function 
  		RTCC_CallBack();
  		
  		IFS3bits.RTCIF = false;
      }
      return status;
  }
  