aboutsummaryrefslogtreecommitdiff
path: root/mirai.old/invocations/os/gettime.zig
blob: 864509325daa2b75e4cb2e41b276a4591008628c (plain)
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);
}