99 lines
3.3 KiB
C
99 lines
3.3 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <sys/cervus.h>
|
|
|
|
static const int MDAYS[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
|
static const char *MNAME[12] = {
|
|
"Jan","Feb","Mar","Apr","May","Jun",
|
|
"Jul","Aug","Sep","Oct","Nov","Dec"
|
|
};
|
|
static const char *WDAY[7] = {"Thu","Fri","Sat","Sun","Mon","Tue","Wed"};
|
|
|
|
static int is_leap(int y) { return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0); }
|
|
static int bcd2bin(int v) { return (v & 0x0F) + ((v >> 4) * 10); }
|
|
|
|
static int cmos_read(int reg)
|
|
{
|
|
if (cervus_ioport_write(0x70, 1, (uint32_t)(reg & 0x7F)) < 0) return -1;
|
|
return (int)(cervus_ioport_read(0x71, 1) & 0xFF);
|
|
}
|
|
static void cmos_wait_ready(void)
|
|
{
|
|
for (int i = 0; i < 2000; i++) {
|
|
cervus_ioport_write(0x70, 1, 0x0A);
|
|
uint32_t sta = cervus_ioport_read(0x71, 1);
|
|
if (!(sta & 0x80)) return;
|
|
}
|
|
}
|
|
|
|
static int64_t rtc_read_unix(void)
|
|
{
|
|
cmos_wait_ready();
|
|
int sec = cmos_read(0x00);
|
|
int min = cmos_read(0x02);
|
|
int hour = cmos_read(0x04);
|
|
int mday = cmos_read(0x07);
|
|
int mon = cmos_read(0x08);
|
|
int year = cmos_read(0x09);
|
|
if (sec < 0 || min < 0 || hour < 0 || mday < 0 || mon < 0 || year < 0) return 0;
|
|
|
|
cervus_ioport_write(0x70, 1, 0x0B);
|
|
int regb = (int)cervus_ioport_read(0x71, 1);
|
|
int binary_mode = (regb >= 0) && (regb & 0x04);
|
|
int hour24 = (regb >= 0) && (regb & 0x02);
|
|
|
|
if (!binary_mode) {
|
|
sec = bcd2bin(sec);
|
|
min = bcd2bin(min);
|
|
mday = bcd2bin(mday);
|
|
mon = bcd2bin(mon);
|
|
year = bcd2bin(year);
|
|
if (!hour24 && (hour & 0x80)) hour = bcd2bin(hour & 0x7F) + 12;
|
|
else hour = bcd2bin(hour);
|
|
}
|
|
year += (year < 70) ? 2000 : 1900;
|
|
if (sec < 0 || sec > 59 || min < 0 || min > 59) return 0;
|
|
if (hour < 0 || hour > 23) return 0;
|
|
if (mday < 1 || mday > 31) return 0;
|
|
if (mon < 1 || mon > 12) return 0;
|
|
if (year < 2000) return 0;
|
|
|
|
int64_t days = 0;
|
|
for (int y = 1970; y < year; y++) days += is_leap(y) ? 366 : 365;
|
|
for (int m = 1; m < mon; m++) days += MDAYS[m-1] + (m == 2 && is_leap(year) ? 1 : 0);
|
|
days += mday - 1;
|
|
return days * 86400LL + (int64_t)hour * 3600LL + (int64_t)min * 60LL + (int64_t)sec;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
(void)argc; (void)argv;
|
|
int64_t t = rtc_read_unix();
|
|
if (t <= 0) {
|
|
uint64_t up = cervus_uptime_ns() / 1000000000ULL;
|
|
fputs(" RTC not available.\n", stdout);
|
|
printf(" Uptime: %lus\n", (unsigned long)up);
|
|
return 0;
|
|
}
|
|
int wday = (int)((t / 86400 + 4) % 7);
|
|
int64_t days = t / 86400;
|
|
int64_t rem = t % 86400;
|
|
if (rem < 0) { rem += 86400; days--; }
|
|
int hour = (int)(rem / 3600);
|
|
int min = (int)((rem % 3600) / 60);
|
|
int sec = (int)(rem % 60);
|
|
|
|
int year = 1970;
|
|
while (1) { int dy = is_leap(year) ? 366 : 365; if (days < dy) break; days -= dy; year++; }
|
|
int mon = 0;
|
|
while (mon < 12) {
|
|
int dm = MDAYS[mon] + (mon == 1 && is_leap(year) ? 1 : 0);
|
|
if (days < dm) break;
|
|
days -= dm; mon++;
|
|
}
|
|
int mday = (int)days + 1;
|
|
printf(" %s %s %2d %02d:%02d:%02d UTC %04d\n",
|
|
WDAY[wday], MNAME[mon], mday, hour, min, sec, year);
|
|
return 0;
|
|
}
|