mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-22 22:12:45 -04:00
Implement RTC write support
* Set local time offset when writing to Joybus or 64DD RTC. * Refactor get_local_time to use ISO C Time APIs. Special thanks to @jago85 and @LuigiBlood for their research!
This commit is contained in:
parent
202d2359c1
commit
8f64dcd8b3
|
@ -293,12 +293,12 @@ set(GDB_SOURCES
|
||||||
set(OS_SOURCES
|
set(OS_SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/os/common/gl_hints.c
|
${PROJECT_SOURCE_DIR}/os/common/gl_hints.c
|
||||||
${PROJECT_SOURCE_DIR}/os/common/input.c
|
${PROJECT_SOURCE_DIR}/os/common/input.c
|
||||||
|
${PROJECT_SOURCE_DIR}/os/common/local_time.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set(OS_POSIX_SOURCES
|
set(OS_POSIX_SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/os/posix/alloc.c
|
${PROJECT_SOURCE_DIR}/os/posix/alloc.c
|
||||||
${PROJECT_SOURCE_DIR}/os/posix/cpuid.c
|
${PROJECT_SOURCE_DIR}/os/posix/cpuid.c
|
||||||
${PROJECT_SOURCE_DIR}/os/posix/local_time.c
|
|
||||||
${PROJECT_SOURCE_DIR}/os/posix/main.c
|
${PROJECT_SOURCE_DIR}/os/posix/main.c
|
||||||
${PROJECT_SOURCE_DIR}/os/posix/rom_file.c
|
${PROJECT_SOURCE_DIR}/os/posix/rom_file.c
|
||||||
${PROJECT_SOURCE_DIR}/os/posix/save_file.c
|
${PROJECT_SOURCE_DIR}/os/posix/save_file.c
|
||||||
|
@ -310,7 +310,6 @@ set(OS_WINAPI_SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/cpuid.c
|
${PROJECT_SOURCE_DIR}/os/winapi/cpuid.c
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/gl_config.c
|
${PROJECT_SOURCE_DIR}/os/winapi/gl_config.c
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/gl_window.c
|
${PROJECT_SOURCE_DIR}/os/winapi/gl_window.c
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/local_time.c
|
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/main.c
|
${PROJECT_SOURCE_DIR}/os/winapi/main.c
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/rom_file.c
|
${PROJECT_SOURCE_DIR}/os/winapi/rom_file.c
|
||||||
${PROJECT_SOURCE_DIR}/os/winapi/save_file.c
|
${PROJECT_SOURCE_DIR}/os/winapi/save_file.c
|
||||||
|
|
|
@ -116,7 +116,6 @@ static void dd_update_bm(struct dd_controller *dd);
|
||||||
static void dd_write_sector(struct dd_controller *dd);
|
static void dd_write_sector(struct dd_controller *dd);
|
||||||
static void dd_read_sector(struct dd_controller *dd);
|
static void dd_read_sector(struct dd_controller *dd);
|
||||||
static void set_offset(struct dd_controller *dd);
|
static void set_offset(struct dd_controller *dd);
|
||||||
static void get_dd_time(uint8_t *out);
|
|
||||||
|
|
||||||
// Initializes the DD.
|
// Initializes the DD.
|
||||||
int dd_init(struct dd_controller *dd, struct bus_controller *bus,
|
int dd_init(struct dd_controller *dd, struct bus_controller *bus,
|
||||||
|
@ -129,6 +128,8 @@ int dd_init(struct dd_controller *dd, struct bus_controller *bus,
|
||||||
dd->retail = true;
|
dd->retail = true;
|
||||||
dd->regs[DD_ASIC_ID_REG] = 0x00030000;
|
dd->regs[DD_ASIC_ID_REG] = 0x00030000;
|
||||||
|
|
||||||
|
dd->rtc_offset_seconds = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,21 +188,47 @@ int write_dd_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) {
|
||||||
|
|
||||||
// Command register written: do something.
|
// Command register written: do something.
|
||||||
if (reg == DD_ASIC_CMD_STATUS) {
|
if (reg == DD_ASIC_CMD_STATUS) {
|
||||||
uint8_t now[6];
|
|
||||||
|
|
||||||
switch (word) {
|
switch (word) {
|
||||||
|
// set time
|
||||||
|
case DD_CMD_SET_YEAR_MONTH:
|
||||||
|
case DD_CMD_SET_DAY_HOUR:
|
||||||
|
case DD_CMD_SET_MIN_SEC: {
|
||||||
|
struct time_stamp now;
|
||||||
|
get_local_time(&now, dd->rtc_offset_seconds);
|
||||||
|
|
||||||
|
if (word == DD_CMD_SET_YEAR_MONTH) {
|
||||||
|
uint8_t year = bcd2byte(dd->regs[DD_ASIC_DATA] >> 24);
|
||||||
|
/* 96-99 map to the 1990's, 00-95 map to 2000+ */
|
||||||
|
now.year = (year >= 96 ? 0 : 100) + year;
|
||||||
|
now.month = bcd2byte(dd->regs[DD_ASIC_DATA] >> 16);
|
||||||
|
} else if (word == DD_CMD_SET_DAY_HOUR) {
|
||||||
|
now.day = bcd2byte(dd->regs[DD_ASIC_DATA] >> 24);
|
||||||
|
now.hour = bcd2byte(dd->regs[DD_ASIC_DATA] >> 16);
|
||||||
|
} else if (word == DD_CMD_SET_MIN_SEC) {
|
||||||
|
now.min = bcd2byte(dd->regs[DD_ASIC_DATA] >> 24);
|
||||||
|
now.sec = bcd2byte(dd->regs[DD_ASIC_DATA] >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
dd->rtc_offset_seconds = get_offset_seconds(&now);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// get time
|
// get time
|
||||||
case DD_CMD_GET_YEAR_MONTH:
|
case DD_CMD_GET_YEAR_MONTH:
|
||||||
case DD_CMD_GET_DAY_HOUR:
|
case DD_CMD_GET_DAY_HOUR:
|
||||||
case DD_CMD_GET_MIN_SEC:
|
case DD_CMD_GET_MIN_SEC: {
|
||||||
get_dd_time(now);
|
struct time_stamp now;
|
||||||
|
get_local_time(&now, dd->rtc_offset_seconds);
|
||||||
|
|
||||||
if (word == DD_CMD_GET_YEAR_MONTH)
|
if (word == DD_CMD_GET_YEAR_MONTH)
|
||||||
dd->regs[DD_ASIC_DATA] = (now[0] << 24) | (now[1] << 16);
|
dd->regs[DD_ASIC_DATA] = (byte2bcd(now.year) << 24) | (byte2bcd(now.month) << 16);
|
||||||
else if (word == DD_CMD_GET_DAY_HOUR)
|
else if (word == DD_CMD_GET_DAY_HOUR)
|
||||||
dd->regs[DD_ASIC_DATA] = (now[2] << 24) | (now[3] << 16);
|
dd->regs[DD_ASIC_DATA] = (byte2bcd(now.day) << 24) | (byte2bcd(now.hour) << 16);
|
||||||
else if (word == DD_CMD_GET_MIN_SEC)
|
else if (word == DD_CMD_GET_MIN_SEC)
|
||||||
dd->regs[DD_ASIC_DATA] = (now[4] << 24) | (now[5] << 16);
|
dd->regs[DD_ASIC_DATA] = (byte2bcd(now.min) << 24) | (byte2bcd(now.sec) << 16);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DD_CMD_SEEK_READ:
|
case DD_CMD_SEEK_READ:
|
||||||
dd->regs[DD_ASIC_CUR_TK] = dd->regs[DD_ASIC_DATA] >> 16;
|
dd->regs[DD_ASIC_CUR_TK] = dd->regs[DD_ASIC_DATA] >> 16;
|
||||||
|
@ -575,19 +602,6 @@ void set_offset(struct dd_controller *dd) {
|
||||||
tr_off * zone_sec_size[dd->zone] * SECTORS_PER_BLOCK * BLOCKS_PER_TRACK;
|
tr_off * zone_sec_size[dd->zone] * SECTORS_PER_BLOCK * BLOCKS_PER_TRACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_dd_time(uint8_t *out) {
|
|
||||||
struct time_stamp now;
|
|
||||||
get_local_time(&now);
|
|
||||||
|
|
||||||
out[0] = byte2bcd(now.year);
|
|
||||||
out[1] = byte2bcd(now.month);
|
|
||||||
out[2] = byte2bcd(now.day);
|
|
||||||
out[3] = byte2bcd(now.hour);
|
|
||||||
out[4] = byte2bcd(now.min);
|
|
||||||
out[5] = byte2bcd(now.sec);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
|
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
|
||||||
|
|
||||||
const struct dd_variant *dd_identify_variant(struct rom_file *ipl) {
|
const struct dd_variant *dd_identify_variant(struct rom_file *ipl) {
|
||||||
|
|
|
@ -51,6 +51,8 @@ struct dd_controller {
|
||||||
uint8_t c2s_buffer[DD_C2S_BUFFER_LEN];
|
uint8_t c2s_buffer[DD_C2S_BUFFER_LEN];
|
||||||
uint8_t ds_buffer[DD_DS_BUFFER_LEN];
|
uint8_t ds_buffer[DD_DS_BUFFER_LEN];
|
||||||
uint8_t ms_ram[DD_MS_RAM_LEN];
|
uint8_t ms_ram[DD_MS_RAM_LEN];
|
||||||
|
|
||||||
|
int32_t rtc_offset_seconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
cen64_cold int dd_init(struct dd_controller *dd, struct bus_controller *bus,
|
cen64_cold int dd_init(struct dd_controller *dd, struct bus_controller *bus,
|
||||||
|
|
51
os/common/local_time.c
Normal file
51
os/common/local_time.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// os/unix/rom_file.c
|
||||||
|
//
|
||||||
|
// Functions for mapping ROM images into the address space.
|
||||||
|
//
|
||||||
|
// This file is subject to the terms and conditions defined in
|
||||||
|
// 'LICENSE', which is part of this source code package.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "local_time.h"
|
||||||
|
|
||||||
|
void get_local_time(struct time_stamp *ts, int32_t offset_seconds) {
|
||||||
|
time_t now = time(NULL);
|
||||||
|
now += offset_seconds;
|
||||||
|
|
||||||
|
struct tm tm = { 0, };
|
||||||
|
#ifdef _WIN32
|
||||||
|
localtime_s(&now, &tm);
|
||||||
|
#else
|
||||||
|
localtime_r(&now, &tm);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Copy tm into time_stamp struct
|
||||||
|
ts->year = tm.tm_year;
|
||||||
|
ts->month = tm.tm_mon + 1; // time_stamp month is zero-indexed
|
||||||
|
ts->day = tm.tm_mday;
|
||||||
|
ts->hour = tm.tm_hour;
|
||||||
|
ts->min = tm.tm_min;
|
||||||
|
ts->sec = tm.tm_sec;
|
||||||
|
ts->week_day = tm.tm_wday;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t get_offset_seconds(const struct time_stamp * ts) {
|
||||||
|
struct tm tm = { 0, };
|
||||||
|
|
||||||
|
// Copy time_stamp into tm struct
|
||||||
|
tm.tm_year = ts->year;
|
||||||
|
tm.tm_mon = ts->month - 1; // time_stamp month is zero-indexed
|
||||||
|
tm.tm_mday = ts->day;
|
||||||
|
tm.tm_hour = ts->hour;
|
||||||
|
tm.tm_min = ts->min;
|
||||||
|
tm.tm_sec = ts->sec;
|
||||||
|
tm.tm_wday = ts->week_day;
|
||||||
|
tm.tm_isdst = -1; // Auto-adjust for DST
|
||||||
|
|
||||||
|
time_t then = mktime(&tm);
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
return then - now;
|
||||||
|
}
|
|
@ -17,22 +17,30 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct time_stamp {
|
struct time_stamp {
|
||||||
unsigned year;
|
// Used by 64DD and Joybus RTC
|
||||||
unsigned month;
|
unsigned year; /* Year starting from 1900 [96-195] */
|
||||||
unsigned day;
|
unsigned month; /* Month [1-12] */
|
||||||
unsigned hour;
|
unsigned day; /* Day [1-31] */
|
||||||
unsigned min;
|
unsigned hour; /* Hour [0-23] */
|
||||||
unsigned sec;
|
unsigned min; /* Minute [0-59] */
|
||||||
|
unsigned sec; /* Second [0-59] */
|
||||||
unsigned week_day;
|
// Used only by Joybus RTC
|
||||||
|
unsigned week_day; /* Day of Week [0-6] (Sun-Sat) */
|
||||||
};
|
};
|
||||||
|
|
||||||
void get_local_time(struct time_stamp *ts);
|
void get_local_time(struct time_stamp *ts, int32_t offset_seconds);
|
||||||
|
|
||||||
|
int32_t get_offset_seconds(const struct time_stamp * ts);
|
||||||
|
|
||||||
static inline uint8_t byte2bcd(unsigned byte) {
|
static inline uint8_t byte2bcd(unsigned byte) {
|
||||||
byte %= 100;
|
byte %= 100;
|
||||||
return ((byte / 10) << 4) | (byte % 10);
|
return ((byte / 10) << 4) | (byte % 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
static inline uint8_t bcd2byte(uint8_t bcd) {
|
||||||
|
uint8_t hi = (bcd & 0xF0) >> 4;
|
||||||
|
uint8_t lo = bcd & 0x0F;
|
||||||
|
return (hi * 10) + lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
//
|
|
||||||
// os/unix/rom_file.c
|
|
||||||
//
|
|
||||||
// Functions for mapping ROM images into the address space.
|
|
||||||
//
|
|
||||||
// This file is subject to the terms and conditions defined in
|
|
||||||
// 'LICENSE', which is part of this source code package.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "local_time.h"
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
void get_local_time(struct time_stamp *ts) {
|
|
||||||
time_t now = time(NULL);
|
|
||||||
struct tm time = { 0, };
|
|
||||||
localtime_r(&now, &time);
|
|
||||||
|
|
||||||
ts->year = time.tm_year;
|
|
||||||
ts->month = time.tm_mon + 1; // month is zero-indexed in this struct
|
|
||||||
ts->day = time.tm_mday;
|
|
||||||
ts->hour = time.tm_hour;
|
|
||||||
ts->min = time.tm_min;
|
|
||||||
ts->sec = time.tm_sec;
|
|
||||||
ts->week_day = time.tm_wday;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// os/winapi/local_time.c: Time functions for Windows.
|
|
||||||
//
|
|
||||||
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
|
|
||||||
// Copyright (C) 2015, Tyler J. Stachecki.
|
|
||||||
//
|
|
||||||
// This file is subject to the terms and conditions defined in
|
|
||||||
// 'LICENSE', which is part of this source code package.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "local_time.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
void get_local_time(struct time_stamp *ts) {
|
|
||||||
SYSTEMTIME sysTime;
|
|
||||||
GetLocalTime(&sysTime);
|
|
||||||
|
|
||||||
ts->year = sysTime.wYear;
|
|
||||||
ts->month = sysTime.wMonth;
|
|
||||||
ts->day = sysTime.wDay;
|
|
||||||
ts->hour = sysTime.wHour;
|
|
||||||
ts->min = sysTime.wMinute;
|
|
||||||
ts->sec = sysTime.wSecond;
|
|
||||||
ts->week_day = sysTime.wDayOfWeek - 1;
|
|
||||||
}
|
|
|
@ -80,6 +80,9 @@ int si_init(struct si_controller *si, struct bus_controller *bus,
|
||||||
si->eeprom.data = eeprom;
|
si->eeprom.data = eeprom;
|
||||||
si->eeprom.size = eeprom_size;
|
si->eeprom.size = eeprom_size;
|
||||||
|
|
||||||
|
// initialize RTC
|
||||||
|
rtc_init(&si->rtc);
|
||||||
|
|
||||||
// controllers
|
// controllers
|
||||||
memcpy(si->controller, controller, sizeof(struct controller) * 4);
|
memcpy(si->controller, controller, sizeof(struct controller) * 4);
|
||||||
|
|
||||||
|
@ -207,7 +210,7 @@ int pif_perform_command(struct si_controller *si,
|
||||||
assert(0 && "Invalid channel for RTC status");
|
assert(0 && "Invalid channel for RTC status");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return rtc_status(send_buf, send_bytes, recv_buf, recv_bytes);
|
return rtc_status(&si->rtc, send_buf, send_bytes, recv_buf, recv_bytes);
|
||||||
|
|
||||||
// RTC read
|
// RTC read
|
||||||
case 0x07:
|
case 0x07:
|
||||||
|
@ -215,7 +218,7 @@ int pif_perform_command(struct si_controller *si,
|
||||||
assert(0 && "Invalid channel for RTC read");
|
assert(0 && "Invalid channel for RTC read");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return rtc_read(send_buf, send_bytes, recv_buf, recv_bytes);
|
return rtc_read(&si->rtc, send_buf, send_bytes, recv_buf, recv_bytes);
|
||||||
|
|
||||||
// RTC write
|
// RTC write
|
||||||
case 0x08:
|
case 0x08:
|
||||||
|
@ -223,7 +226,7 @@ int pif_perform_command(struct si_controller *si,
|
||||||
assert(0 && "Invalid channel for RTC write");
|
assert(0 && "Invalid channel for RTC write");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return rtc_write(send_buf, send_bytes, recv_buf, recv_bytes);
|
return rtc_write(&si->rtc, send_buf, send_bytes, recv_buf, recv_bytes);
|
||||||
|
|
||||||
// Unimplemented command:
|
// Unimplemented command:
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#ifndef __si_controller_h__
|
#ifndef __si_controller_h__
|
||||||
#define __si_controller_h__
|
#define __si_controller_h__
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "local_time.h"
|
||||||
#include "si/pak.h"
|
#include "si/pak.h"
|
||||||
#include "dd/controller.h"
|
#include "dd/controller.h"
|
||||||
|
|
||||||
|
@ -30,6 +31,12 @@ struct eeprom {
|
||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct rtc {
|
||||||
|
uint16_t control;
|
||||||
|
struct time_stamp now;
|
||||||
|
int32_t offset_seconds;
|
||||||
|
};
|
||||||
|
|
||||||
struct si_controller {
|
struct si_controller {
|
||||||
struct bus_controller *bus;
|
struct bus_controller *bus;
|
||||||
const uint8_t *rom;
|
const uint8_t *rom;
|
||||||
|
@ -40,6 +47,7 @@ struct si_controller {
|
||||||
uint32_t pif_status;
|
uint32_t pif_status;
|
||||||
uint8_t input[4];
|
uint8_t input[4];
|
||||||
struct eeprom eeprom;
|
struct eeprom eeprom;
|
||||||
|
struct rtc rtc;
|
||||||
struct controller controller[4];
|
struct controller controller[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
115
si/rtc.c
115
si/rtc.c
|
@ -10,56 +10,127 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "local_time.h"
|
#include "local_time.h"
|
||||||
|
#include "si/controller.h"
|
||||||
|
|
||||||
int rtc_status(uint8_t *send_buf, uint8_t send_bytes,
|
static inline uint8_t rtc_status_byte(struct rtc * rtc) {
|
||||||
|
return (rtc->control & 0x0004) ? 0x80 : 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_init(struct rtc * rtc) {
|
||||||
|
// Write-protected, not stopped
|
||||||
|
rtc->control = 0x0300;
|
||||||
|
rtc->offset_seconds = 0;
|
||||||
|
get_local_time(&rtc->now, rtc->offset_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtc_status(struct rtc * rtc,
|
||||||
|
uint8_t *send_buf, uint8_t send_bytes,
|
||||||
uint8_t *recv_buf, uint8_t recv_bytes) {
|
uint8_t *recv_buf, uint8_t recv_bytes) {
|
||||||
|
// Check send/recv buffer lengths
|
||||||
|
assert(send_bytes == 1);
|
||||||
|
assert(recv_bytes == 3);
|
||||||
|
|
||||||
recv_buf[0] = 0x00;
|
recv_buf[0] = 0x00;
|
||||||
recv_buf[1] = 0x10;
|
recv_buf[1] = 0x10;
|
||||||
recv_buf[2] = 0x00;
|
recv_buf[2] = rtc_status_byte(rtc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtc_read(uint8_t *send_buf, uint8_t send_bytes,
|
int rtc_read(struct rtc * rtc,
|
||||||
|
uint8_t *send_buf, uint8_t send_bytes,
|
||||||
uint8_t *recv_buf, uint8_t recv_bytes) {
|
uint8_t *recv_buf, uint8_t recv_bytes) {
|
||||||
struct time_stamp now;
|
// Check send/recv buffer lengths
|
||||||
|
assert(send_bytes == 2);
|
||||||
|
assert(recv_bytes == 9);
|
||||||
|
|
||||||
// FIXME is this needed?
|
// Zero out the response buffer
|
||||||
memset(recv_buf, 0, recv_bytes);
|
memset(recv_buf, 0, recv_bytes);
|
||||||
|
|
||||||
// read RTC block
|
// read RTC block
|
||||||
switch (send_buf[1]) {
|
switch (send_buf[1]) {
|
||||||
case 0:
|
case 0:
|
||||||
recv_buf[0] = 0x02;
|
recv_buf[0] = rtc->control >> 8;
|
||||||
|
recv_buf[1] = rtc->control;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
debug("RTC cannot read block 1\n");
|
debug("RTC read block 1 is not implemented\n");
|
||||||
return 1;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
get_local_time(&now);
|
// update the time if the clock is not stopped
|
||||||
recv_buf[0] = byte2bcd(now.sec);
|
if ((rtc->control & 0x0004) == 0) {
|
||||||
recv_buf[1] = byte2bcd(now.min);
|
get_local_time(&rtc->now, rtc->offset_seconds);
|
||||||
recv_buf[2] = 0x80 + byte2bcd(now.hour);
|
}
|
||||||
recv_buf[3] = byte2bcd(now.day);
|
recv_buf[0] = byte2bcd(rtc->now.sec);
|
||||||
recv_buf[4] = byte2bcd(now.week_day);
|
recv_buf[1] = byte2bcd(rtc->now.min);
|
||||||
recv_buf[5] = byte2bcd(now.month);
|
recv_buf[2] = byte2bcd(rtc->now.hour) + 0x80;
|
||||||
recv_buf[6] = byte2bcd(now.year);
|
recv_buf[3] = byte2bcd(rtc->now.day);
|
||||||
recv_buf[7] = byte2bcd(now.year / 100);
|
recv_buf[4] = byte2bcd(rtc->now.week_day);
|
||||||
recv_buf[8] = 0x00; // status
|
recv_buf[5] = byte2bcd(rtc->now.month);
|
||||||
|
recv_buf[6] = byte2bcd(rtc->now.year);
|
||||||
|
recv_buf[7] = byte2bcd(rtc->now.year / 100);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
debug("RTC unknown block\n");
|
debug("RTC read invalid block\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recv_buf[8] = rtc_status_byte(rtc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtc_write(uint8_t *send_buf, uint8_t send_bytes,
|
int rtc_write(struct rtc * rtc,
|
||||||
|
uint8_t *send_buf, uint8_t send_bytes,
|
||||||
uint8_t *recv_buf, uint8_t recv_bytes) {
|
uint8_t *recv_buf, uint8_t recv_bytes) {
|
||||||
debug("RTC write not implemented\n");
|
// Check send/recv buffer lengths
|
||||||
return 1;
|
assert(send_bytes == 10);
|
||||||
|
assert(recv_bytes == 1);
|
||||||
|
|
||||||
|
// write RTC block
|
||||||
|
switch (send_buf[1]) {
|
||||||
|
case 0:
|
||||||
|
rtc->control = ((uint16_t)send_buf[2] << 8) | send_buf[3];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if (rtc->control & 0x0100) {
|
||||||
|
debug("RTC write block 1 is write-protected\n");
|
||||||
|
} else {
|
||||||
|
debug("RTC write block 1 is not implemented\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if ((rtc->control & 0x0004) == 0) {
|
||||||
|
debug("RTC write block 2 while clock is running\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rtc->control & 0x0200) {
|
||||||
|
debug("RTC write block 2 is write-protected\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rtc->now.sec = bcd2byte(send_buf[2]);
|
||||||
|
rtc->now.min = bcd2byte(send_buf[3]);
|
||||||
|
rtc->now.hour = bcd2byte(send_buf[4] - 0x80);
|
||||||
|
rtc->now.day = bcd2byte(send_buf[5]);
|
||||||
|
rtc->now.week_day = bcd2byte(send_buf[6]);
|
||||||
|
rtc->now.month = bcd2byte(send_buf[7]);
|
||||||
|
rtc->now.year = bcd2byte(send_buf[8]);
|
||||||
|
rtc->now.year += bcd2byte(send_buf[9]) * 100;
|
||||||
|
// Set the clock offset based on current local time
|
||||||
|
rtc->offset_seconds = get_offset_seconds(&rtc->now);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
debug("RTC write invalid block\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_buf[0] = rtc_status_byte(rtc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
11
si/rtc.h
11
si/rtc.h
|
@ -11,12 +11,17 @@
|
||||||
#ifndef __si_rtc_h__
|
#ifndef __si_rtc_h__
|
||||||
#define __si_rtc_h__
|
#define __si_rtc_h__
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "si/controller.h"
|
||||||
|
|
||||||
int rtc_status(uint8_t *send_buf, uint8_t send_bytes,
|
void rtc_init(struct rtc * rtc);
|
||||||
|
int rtc_status(struct rtc * rtc,
|
||||||
|
uint8_t *send_buf, uint8_t send_bytes,
|
||||||
uint8_t *recv_buf, uint8_t recv_bytes);
|
uint8_t *recv_buf, uint8_t recv_bytes);
|
||||||
int rtc_read(uint8_t *send_buf, uint8_t send_bytes,
|
int rtc_read(struct rtc * rtc,
|
||||||
|
uint8_t *send_buf, uint8_t send_bytes,
|
||||||
uint8_t *recv_buf, uint8_t recv_bytes);
|
uint8_t *recv_buf, uint8_t recv_bytes);
|
||||||
int rtc_write(uint8_t *send_buf, uint8_t send_bytes,
|
int rtc_write(struct rtc * rtc,
|
||||||
|
uint8_t *send_buf, uint8_t send_bytes,
|
||||||
uint8_t *recv_buf, uint8_t recv_bytes);
|
uint8_t *recv_buf, uint8_t recv_bytes);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue