1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
//! GETTIME invocation - Get current unix timestamp
const cmos = @import("../../asm/cmos.zig");
const handler = @import("../handler.zig");
const result = @import("../../utils/types/result.zig");
const sensei = @import("../../kata/sensei/sensei.zig");
const time_const = @import("../../common/constants/time.zig");
var boot_timestamp: u64 = 0;
pub fn set_boot_timestamp(timestamp: u64) void {
boot_timestamp = timestamp;
}
pub fn invoke(ctx: *handler.InvocationContext) void {
if (boot_timestamp == 0) {
const rtc_time = read_rtc();
result.set_value(ctx, rtc_time);
} else {
const ticks = sensei.get_tick_count();
const seconds = ticks / time_const.TICKS_PER_SECOND;
result.set_value(ctx, boot_timestamp + seconds);
}
}
fn read_rtc() u64 {
const sec = cmos.bcd_to_bin(cmos.read_seconds());
const min = cmos.bcd_to_bin(cmos.read_minutes());
const hr = cmos.bcd_to_bin(cmos.read_hours());
const d = cmos.bcd_to_bin(cmos.read_day());
const m = cmos.bcd_to_bin(cmos.read_month());
const y = cmos.bcd_to_bin(cmos.read_year());
const c = cmos.bcd_to_bin(cmos.read_century());
const full_year = @as(u64, c) * 100 + @as(u64, y);
return to_unix_timestamp(full_year, m, d, hr, min, sec);
}
fn to_unix_timestamp(year: u64, month: u8, day: u8, hour: u8, minute: u8, second: u8) u64 {
const DAYS_BEFORE_MONTH = [_]u64{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
var days: u64 = 0;
// Days from years since 1970
var y = time_const.EPOCH_YEAR;
while (y < year) : (y += 1) {
days += if (is_leap(y)) 366 else 365;
}
// Days from months
if (month > 0 and month <= 12) {
days += DAYS_BEFORE_MONTH[month - 1];
}
// Add leap day if past February in a leap year
if (month > 2 and is_leap(year)) {
days += 1;
}
// Days in current month
days += day - 1;
return days * time_const.SECONDS_PER_DAY +
@as(u64, hour) * time_const.SECONDS_PER_HOUR +
@as(u64, minute) * time_const.SECONDS_PER_MINUTE +
@as(u64, second);
}
fn is_leap(year: u64) bool {
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0);
}
|