text: //
  //  time.c
  //  BetaOS
  //
  //  Created by Adam Kopeć on 11/30/15.
  //  Copyright © 2015-2017 Adam Kopeć. All rights reserved.
  //
  
  #include <time.h>
  #include <math.h>
  #include <i386/pio.h>
  
  #define CURRENT_CENTURY 21
  
  unsigned char second;
  unsigned char minute;
  unsigned char hour;
  unsigned char day;
  unsigned char month;
  unsigned int year;
  char* pmam;
  char* monthl;
  char* dayofweekshort;
  char* dayofweeklong;
  
  static int century_register = 0x00;
  
  void read_rtc(void);
  enum {
      cmos_address = 0x70,
      cmos_data    = 0x71
  };
  
  int get_update_in_progress_flag(void);
  unsigned char get_RTC_register(int reg);
  
  
  //absolute_time_t absolute_UNIX = 0; // 0 - 1 January 1970
  //absolute_time_t absolute_Beta = 0;
  time_t absolute_UNIX = 0; // 0 - 1 January 1970
  time_t absolute_Beta = 0;
  //
  #define Is_leap_yearUNIX(y)   (((1970+y)>0) && (!((1970+y)%4)) && (((1970+y)%100) || (!((1970+y)%400))))
  #define Is_leap_year(y)  (((y)>0) && (!((y)%4)) && (((y)%100) || (!((y)%400))))
  #define Seconds_in_a_day    86400
  #define Seconds_in_an_hour   3600
  #define Seconds_in_a_minute    60
  //
  static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
  //
  
  //static inline bool Is_leap_year(int y) {
  //    float Year = y;
  //    if (fmodf(Year, 4) == 0.00) {
  //        if (fmodf(Year, 100) == 0.00) {
  //            if (fmodf(Year, 400) == 0.00)
  //                return true;
  //            else
  //                return false;
  //        } else
  //            return true;
  //    } else
  //        return false;
  //}
  
  time_t time(time_t * value) {
      read_rtc();
      absolute_UNIX = (year - 1970) * (Seconds_in_a_day * 365);
      for (uint32_t i = 1971; i < year; i++) {
          if (Is_leap_yearUNIX(i)) {
              absolute_UNIX += Seconds_in_a_day;
          }
      }
      for (uint32_t i = 0; i < month-1; i++) {
          if ((i == 1) && Is_leap_year(year)) {
              absolute_UNIX += Seconds_in_a_day * 29;
          } else {
              absolute_UNIX += Seconds_in_a_day * monthDays[i];
          }
      }
      absolute_UNIX += day    * Seconds_in_a_day;
      absolute_UNIX += hour   * Seconds_in_an_hour;
      absolute_UNIX += minute * Seconds_in_a_minute;
      absolute_UNIX += second;
      if (value != NULL) {
          *value = absolute_UNIX;
      }
      return absolute_UNIX;
  }
  
  int get_update_in_progress_flag() {
      outb(cmos_address, 0x0A);
      return (inb(cmos_data) & 0x80);
  }
  
  unsigned char get_RTC_register(int reg) {
      outb(cmos_address, reg);
      return inb(cmos_data);
  }
  
  void read_rtc() {
      unsigned char century=21;
      unsigned char last_second;
      unsigned char last_minute;
      unsigned char last_hour;
      unsigned char last_day;
      unsigned char last_month;
      unsigned char last_year;
      unsigned char last_century;
      unsigned char registerB;
  
  
      while (get_update_in_progress_flag());
      second = get_RTC_register(0x00);
      minute = get_RTC_register(0x02);
      hour = get_RTC_register(0x04);
      day = get_RTC_register(0x07);
      month = get_RTC_register(0x08);
      year = get_RTC_register(0x09);
      if(century_register != 0) {
          century = get_RTC_register(century_register);
      }
  
      do {
          last_second = second;
          last_minute = minute;
          last_hour = hour;
          last_day = day;
          last_month = month;
          last_year = year;
          last_century = century;
  
          while (get_update_in_progress_flag());
          second = get_RTC_register(0x00);
          minute = get_RTC_register(0x02);
          hour = get_RTC_register(0x04);
          day = get_RTC_register(0x07);
          month = get_RTC_register(0x08);
          year = get_RTC_register(0x09);
          if(century_register != 0) {
              century = get_RTC_register(century_register);
          }
      } while( (last_second != second) || (last_minute != minute) || (last_hour != hour) ||
              (last_day != day) || (last_month != month) || (last_year != year) ||
              (last_century != century) );
  
      registerB = get_RTC_register(0x0B);
  
  
      if (!(registerB & 0x04)) {
          second = (second & 0x0F) + ((second / 16) * 10);
          minute = (minute & 0x0F) + ((minute / 16) * 10);
          hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);
          day = (day & 0x0F) + ((day / 16) * 10);
          month = (month & 0x0F) + ((month / 16) * 10);
          year = (year & 0x0F) + ((year / 16) * 10);
          if(century_register != 0) {
              century = (century & 0x0F) + ((century / 16) * 10);
          }
      }
  
  
      if (!(registerB & 0x02) && (hour & 0x80)) {
          hour = ((hour & 0x7F) + 12) % 24;
      }
  
  
      if(century_register != 0) {
          year += century * 100;
      } else {
          year += (CURRENT_CENTURY-1) * 100;
      }
  }
  
  // FIXME: Don't use this ugly hack
  #include <stdio.h>
  extern bool early;
  struct tm *gmtime_r(const time_t * timer __unused, struct tm * ptm) {
      ptm->tm_hour = hour;
      ptm->tm_min  = minute;
      ptm->tm_sec  = second;
      ptm->tm_mday = day;
      ptm->tm_mon  = month;
      ptm->tm_year = year - 1900;
      int y = year;
      static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
      y -= month < 3;
      int dayofweek = (y + y/4 - y/100 + y/400 + t[month-1] + day) % 7;
      ptm->tm_wday = dayofweek;
      early = true;
      printf("H: %d M: %d S: %d D: %d m: %d Y: %d W: %d\n", hour, minute, second, day, month, year - 1900, dayofweek);
      early = false;
      return ptm;
  }
  
  struct tm *gmtime(const time_t * timer) {
      struct tm time;
      return gmtime_r(timer, &time);
  }
  //
  //void translateMonth() {
  //    switch (month) {
  //        case 1:
  //            monthl="January";
  //            break;
  //        case 2:
  //            monthl="February";
  //            break;
  //        case 3:
  //            monthl="March";
  //            break;
  //        case 4:
  //            monthl="April";
  //            break;
  //        case 5:
  //            monthl="May";
  //            break;
  //        case 6:
  //            monthl="June";
  //            break;
  //        case 7:
  //            monthl="July";
  //            break;
  //        case 8:
  //            monthl="August";
  //            break;
  //        case 9:
  //            monthl="September";
  //            break;
  //        case 10:
  //            monthl="October";
  //            break;
  //        case 11:
  //            monthl="November";
  //            break;
  //        case 12:
  //            monthl="December";
  //            break;
  //
  //        default:
  //            break;
  //    }
  //}
  //
  //void translateDay() {
  //    int y = year;
  //    static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
  //    y -= month < 3;
  //    int dayofweek = (y + y/4 - y/100 + y/400 + t[month-1] + day) % 7;
  //
  //    switch (dayofweek) {
  //        case 0:
  //            dayofweeklong = "Sunday";
  //            dayofweekshort = "Sun";
  //            break;
  //        case 1:
  //            dayofweeklong = "Monday";
  //            dayofweekshort = "Mon";
  //            break;
  //        case 2:
  //            dayofweeklong = "Tuesday";
  //            dayofweekshort = "Tue";
  //            break;
  //        case 3:
  //            dayofweeklong = "Wednesday";
  //            dayofweekshort = "Wed";
  //            break;
  //        case 4:
  //            dayofweeklong = "Thursday";
  //            dayofweekshort = "Thu";
  //            break;
  //        case 5:
  //            dayofweeklong = "Friday";
  //            dayofweekshort = "Fri";
  //            break;
  //        case 6:
  //            dayofweeklong = "Saturday";
  //            dayofweekshort = "Sat";
  //            break;
  //        default:
  //            break;
  //    }
  //}
  //void translateHour() {
  //    if (hour<12 && hour>0) {
  //        pmam="AM";
  //    } else if (hour>12 && hour<24) {
  //        hour-=12;
  //        pmam="PM";
  //    } else if (hour==12) {
  //        pmam="PM";
  //    } else if (hour==0 || hour==24) {
  //        hour=12;
  //        pmam="AM";
  //    }
  //}
  //
  //void gettime() {
  //    read_rtc();
  //    translateHour();
  //    translateDay();
  //    translateMonth();
  //}
  
  