mirror of
https://github.com/kenshineto/kern.git
synced 2025-04-16 23:47:25 +00:00
real time clock
This commit is contained in:
parent
3c2a519ee9
commit
3a44b8da25
7 changed files with 393 additions and 0 deletions
|
@ -30,6 +30,7 @@ const kernel_src = &[_][]const u8{
|
|||
"kernel/cpu/idt.c",
|
||||
"kernel/cpu/idt.S",
|
||||
"kernel/cpu/pic.c",
|
||||
"kernel/drivers/clock.c",
|
||||
"kernel/drivers/drivers.c",
|
||||
"kernel/drivers/pci.c",
|
||||
"kernel/drivers/tty.c",
|
||||
|
@ -71,6 +72,7 @@ const lib_src = &[_][]const u8{
|
|||
"lib/strncpy.c",
|
||||
"lib/strtoux.c",
|
||||
"lib/strtox.c",
|
||||
"lib/timetostr.c",
|
||||
"lib/uxtoa.c",
|
||||
"lib/xtoa.c",
|
||||
};
|
||||
|
|
63
include/time.h
Normal file
63
include/time.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* @file time.h
|
||||
*
|
||||
* @author Freya Murphy <freya@freyacat.org>
|
||||
*
|
||||
* System time structure
|
||||
*/
|
||||
|
||||
#ifndef TIME_H_
|
||||
#define TIME_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
int sec; /// Seconds [0,59]
|
||||
int min; /// Minutes [0,59]
|
||||
int hour; /// Hour [0,23]
|
||||
int mday; /// Day of month [1,31]
|
||||
int mon; /// Month of year [0,11]
|
||||
int year; /// Years since 1900
|
||||
int wday; /// Day of week [0,6] (Sunday = 0)
|
||||
int yday; /// Day of year [0,365]
|
||||
int yn; /// Year number [0,99]
|
||||
int cen; /// Century [19,20]
|
||||
int leap; /// If year is a leap year (True == 1)
|
||||
} time_t;
|
||||
|
||||
typedef enum {
|
||||
TZ_UTC = 0,
|
||||
TZ_EST = -5,
|
||||
TZ_EDT = -4,
|
||||
} timezone_t;
|
||||
|
||||
/**
|
||||
* Sets the current timezone
|
||||
*/
|
||||
extern void set_timezone(timezone_t tz);
|
||||
|
||||
/**
|
||||
* Returns current time in UTC
|
||||
*/
|
||||
extern time_t get_utctime(void);
|
||||
|
||||
/**
|
||||
* Returns current time from current Timezone
|
||||
*/
|
||||
extern time_t get_localtime(void);
|
||||
|
||||
/**
|
||||
* Return the time on the system clock
|
||||
*/
|
||||
extern size_t get_systemtime(void);
|
||||
|
||||
/**
|
||||
* Converts the time into a string format
|
||||
*
|
||||
* @param time - the current time
|
||||
* @param format - see manpage for date
|
||||
* @param buf - the buffer to store it in
|
||||
*/
|
||||
extern void timetostr(time_t *time, char *format, char *buf, size_t n);
|
||||
|
||||
#endif /* time.h */
|
159
kernel/drivers/clock.c
Normal file
159
kernel/drivers/clock.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include <lib.h>
|
||||
#include <time.h>
|
||||
#include <comus/asm.h>
|
||||
#include <comus/drivers/clock.h>
|
||||
|
||||
#define CMOS_WRITE_PORT 0x70
|
||||
#define CMOS_READ_PORT 0x71
|
||||
|
||||
#define CMOS_REG_SEC 0x00
|
||||
#define CMOS_REG_MIN 0x02
|
||||
#define CMOS_REG_HOUR 0x04
|
||||
#define CMOS_REG_WDAY 0x06
|
||||
#define CMOS_REG_MDAY 0x07
|
||||
#define CMOS_REG_MON 0x08
|
||||
#define CMOS_REG_YEAR 0x09
|
||||
#define CMOS_REG_CEN 0x32
|
||||
|
||||
// Live buffers to work on data
|
||||
static time_t time;
|
||||
static time_t localtime;
|
||||
|
||||
// Front buffers so interupts dont request data that is half done
|
||||
static time_t curr_time;
|
||||
static time_t curr_localtime;
|
||||
|
||||
// Current set time Zone
|
||||
static timezone_t curr_timezone = TZ_UTC;
|
||||
static timezone_t last_timezone = TZ_UTC;
|
||||
|
||||
static uint8_t cmos_read(uint8_t reg) {
|
||||
uint8_t hex, ret;
|
||||
|
||||
outb(CMOS_WRITE_PORT, reg);
|
||||
hex = inb(CMOS_READ_PORT);
|
||||
|
||||
ret = hex & 0x0F;
|
||||
ret += (hex & 0xF0) / 16 * 10;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mday_offset[12] = {
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
||||
};
|
||||
|
||||
static int month_days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
static void update_localtime(void) {
|
||||
|
||||
int change, max;
|
||||
|
||||
// set localtime
|
||||
localtime = time;
|
||||
|
||||
// if tz is UTC, we dont need to do anythin
|
||||
if (last_timezone == TZ_UTC) return;
|
||||
|
||||
localtime.hour += last_timezone;
|
||||
|
||||
// check if day rolled over
|
||||
change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
|
||||
if (!change) return;
|
||||
|
||||
// roll over day
|
||||
localtime.hour = (localtime.hour + 24) % 24;
|
||||
localtime.wday = (localtime.wday + change + 7) % 7;
|
||||
localtime.mday += change;
|
||||
localtime.yday += change;
|
||||
|
||||
// check if month rolled over
|
||||
max = month_days[localtime.mon];
|
||||
if (localtime.leap && localtime.mon == 1) max++;
|
||||
change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0;
|
||||
if (!change) return;
|
||||
|
||||
// roll over month
|
||||
localtime.mon = (localtime.mon + change + 12) % 12;
|
||||
|
||||
// check if year rolled over
|
||||
max = localtime.leap ? 366 : 365;
|
||||
change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0;
|
||||
if (!change) return;
|
||||
|
||||
// roll over year
|
||||
localtime.yn += change;
|
||||
|
||||
// check if cen rolled over
|
||||
change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0;
|
||||
if (!change) goto year;
|
||||
|
||||
// roll over cen
|
||||
localtime.cen += change;
|
||||
|
||||
|
||||
year:
|
||||
|
||||
localtime.year = localtime.yn + localtime.cen * 100;
|
||||
localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0;
|
||||
|
||||
if (localtime.leap && localtime.yday == -1)
|
||||
localtime.yday = 365;
|
||||
else if (localtime.yday == -1)
|
||||
localtime.yday = 364;
|
||||
else
|
||||
localtime.yday = 0;
|
||||
|
||||
localtime.year -= 1900;
|
||||
|
||||
}
|
||||
|
||||
void clock_update(void) {
|
||||
time.sec = cmos_read(CMOS_REG_SEC);
|
||||
time.min = cmos_read(CMOS_REG_MIN);
|
||||
time.hour = cmos_read(CMOS_REG_HOUR);
|
||||
time.wday = cmos_read(CMOS_REG_WDAY) - 1;
|
||||
time.mday = cmos_read(CMOS_REG_MDAY);
|
||||
time.mon = cmos_read(CMOS_REG_MON) - 1;
|
||||
time.yn = cmos_read(CMOS_REG_YEAR);
|
||||
time.cen = 20;
|
||||
|
||||
time.year = time.yn + time.cen * 100;
|
||||
|
||||
time.leap = time.year % 4 == 0 && time.year % 100 != 0;
|
||||
|
||||
time.yday = mday_offset[time.mon] + time.mday;
|
||||
|
||||
if (time.leap && time.mon > 2)
|
||||
time.yday++;
|
||||
|
||||
time.year -= 1900;
|
||||
|
||||
update_localtime();
|
||||
|
||||
curr_time = time;
|
||||
curr_localtime = localtime;
|
||||
}
|
||||
|
||||
void set_timezone(timezone_t tz) {
|
||||
curr_timezone = tz;
|
||||
}
|
||||
|
||||
time_t get_utctime(void) {
|
||||
return curr_time;
|
||||
}
|
||||
|
||||
time_t get_localtime(void) {
|
||||
if (curr_timezone != last_timezone) {
|
||||
last_timezone = curr_timezone;
|
||||
update_localtime();
|
||||
curr_localtime = localtime;
|
||||
}
|
||||
return curr_localtime;
|
||||
}
|
||||
|
||||
size_t get_systemtime(void) {
|
||||
return 0;
|
||||
}
|
|
@ -2,10 +2,12 @@
|
|||
#include <comus/drivers/uart.h>
|
||||
#include <comus/drivers/tty.h>
|
||||
#include <comus/drivers/pci.h>
|
||||
#include <comus/drivers/clock.h>
|
||||
|
||||
void drivers_init(void)
|
||||
{
|
||||
uart_init();
|
||||
tty_init();
|
||||
pci_init();
|
||||
clock_update();
|
||||
}
|
||||
|
|
14
kernel/include/comus/drivers/clock.h
Normal file
14
kernel/include/comus/drivers/clock.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* @file clock.h
|
||||
*
|
||||
* @author Freya Murphy <freya@freyacat.org>
|
||||
*
|
||||
* CMOS real time clock driver
|
||||
*/
|
||||
|
||||
#ifndef CLOCK_H_
|
||||
#define CLOCK_H_
|
||||
|
||||
extern void clock_update(void);
|
||||
|
||||
#endif /* clock.h */
|
|
@ -3,6 +3,8 @@
|
|||
#include <comus/mboot.h>
|
||||
#include <comus/drivers.h>
|
||||
#include <lib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
struct memory_map mmap;
|
||||
|
||||
|
@ -23,6 +25,13 @@ void main(long magic, volatile void *mboot)
|
|||
// initalize devices
|
||||
drivers_init();
|
||||
|
||||
// print current time
|
||||
char date[40];
|
||||
set_timezone(TZ_EDT);
|
||||
time_t time = get_localtime();
|
||||
timetostr(&time, "%a %b %d %Y %H:%M:%S", date, 40);
|
||||
printf("The date is: %s\n\n", date);
|
||||
|
||||
// halt
|
||||
printf("halting...\n");
|
||||
}
|
||||
|
|
144
lib/timetostr.c
Normal file
144
lib/timetostr.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include <lib.h>
|
||||
#include <time.h>
|
||||
|
||||
static char* ABB_WEEKDAY[7] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
|
||||
static char* FULL_WEEKDAY[7] = {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturady"
|
||||
};
|
||||
|
||||
static char* ABB_MONTH[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
static char* FULL_MONTH[12] = {
|
||||
"January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
|
||||
};
|
||||
|
||||
static char *write_num(unsigned int num, unsigned int pad, char *buf, size_t n) {
|
||||
size_t digits = 1;
|
||||
unsigned int x = num;
|
||||
|
||||
while (x /= 10, x > 0) digits++;
|
||||
if (pad == 0) pad = digits;
|
||||
|
||||
for (size_t i = 0; i < pad; i++) {
|
||||
|
||||
size_t digit;
|
||||
if (i >= digits) {
|
||||
digit = 0;
|
||||
} else {
|
||||
digit = num % 10;
|
||||
num /= 10;
|
||||
}
|
||||
|
||||
if (pad - i - 1 >= n) continue;
|
||||
buf[pad - i - 1] = '0' + digit;
|
||||
|
||||
}
|
||||
|
||||
if (pad > n) pad = n;
|
||||
|
||||
return buf + pad;
|
||||
}
|
||||
|
||||
void timetostr(time_t *time, char *format, char *buf, size_t n) {
|
||||
char *index = buf;
|
||||
char c;
|
||||
int space;
|
||||
|
||||
while (
|
||||
c = *format++,
|
||||
space = (buf + n) - index,
|
||||
c != '\0' && space > 0
|
||||
) {
|
||||
if (c != '%') {
|
||||
*index++ = c;
|
||||
continue;
|
||||
} else {
|
||||
c = *format++;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '%':
|
||||
*index++ = '%';
|
||||
break;
|
||||
case 'a':
|
||||
index = strncpy(index, ABB_WEEKDAY[time->wday], space);
|
||||
break;
|
||||
case 'A':
|
||||
index = strncpy(index, FULL_WEEKDAY[time->wday], space);
|
||||
break;
|
||||
case 'b':
|
||||
case 'h':
|
||||
index = strncpy(index, ABB_MONTH[time->mon], space);
|
||||
break;
|
||||
case 'B':
|
||||
index = strncpy(index, FULL_MONTH[time->mon], space);
|
||||
break;
|
||||
case 'C':
|
||||
index = write_num(time->cen, 0, index, space);
|
||||
break;
|
||||
case 'd':
|
||||
index = write_num(time->mday, 2, index, space);
|
||||
break;
|
||||
case 'H':
|
||||
index = write_num(time->hour, 2, index, space);
|
||||
break;
|
||||
case 'I':
|
||||
index = write_num((time->hour + 12) % 12 + 1, 2, index, space);
|
||||
break;
|
||||
case 'j':
|
||||
index = write_num(time->yday, 3, index, space);
|
||||
break;
|
||||
case 'm':
|
||||
index = write_num(time->mon + 1, 2, index, space);
|
||||
break;
|
||||
case 'M':
|
||||
index = write_num(time->min, 2, index, space);
|
||||
break;
|
||||
case 'n':
|
||||
*index++ = '\n';
|
||||
break;
|
||||
case 'p':
|
||||
index = strncpy(index, time->hour > 11 ? "PM" : "AM", space);
|
||||
break;
|
||||
case 'P':
|
||||
index = strncpy(index, time->hour > 11 ? "pm" : "am", space);
|
||||
break;
|
||||
case 'q':
|
||||
index = write_num((time->mon + 3) / 3, 0, index, space);
|
||||
break;
|
||||
case 'S':
|
||||
index = write_num(time->sec, 2, index, space);
|
||||
break;
|
||||
case 't':
|
||||
*index++ = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
index = write_num(((time->wday + 1 )% 7) + 1, 0, index, space);
|
||||
break;
|
||||
case 'w':
|
||||
index = write_num(time->wday, 0, index, space);
|
||||
break;
|
||||
case 'y':
|
||||
index = write_num(time->yn, 2, index, space);
|
||||
break;
|
||||
case 'Y':
|
||||
index = write_num(time->year + 1900, 0, index, space);
|
||||
break;
|
||||
default: {
|
||||
char b[3] = {'%', c, '\0'};
|
||||
index = strncpy(index, b, space);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (space < 1)
|
||||
buf[n - 1] = '\0';
|
||||
else
|
||||
*index = '\0';
|
||||
}
|
Loading…
Add table
Reference in a new issue