mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-24 11:39:17 +01:00
Add ability to adjust RTC (#107)
<!--- Provide a general summary of your changes in the Title above --> ## Description <!--- Describe your changes in detail --> This PR adds the ability to set the time from the menu. The underlying logic is sound given what is currently available within libdragon, but expected changes are noted (like `settimeofday`) for future improvement and will need to be revisited once available. A future PR will need to add better GUI components for numeric control. ## Motivation and Context <!--- What does this sample do? What problem does it solve? --> <!--- If it fixes/closes/resolves an open issue, please link to the issue here --> #106 ## How Has This Been Tested? <!-- (if applicable) --> <!--- Please describe in detail how you tested your sample/changes. --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> locally on a SC64 ## Screenshots <!-- (if appropriate): --> ## Types of changes <!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: <!--- Go over all the following points, and put an `x` in all the boxes that apply. --> <!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. <!--- It would be nice if you could sign off your contribution by replacing the name with your GitHub user name and GitHub email contact. --> Signed-off-by: GITHUB_USER <GITHUB_USER_EMAIL>
This commit is contained in:
parent
17c214537f
commit
e7608dc557
@ -1,26 +1,165 @@
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <libdragon.h>
|
||||
#include <sys/time.h>
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
// FIXME: add implementation!
|
||||
// struct {
|
||||
// uint16_t seconds;
|
||||
// uint16_t minutes;
|
||||
// uint16_t hours;
|
||||
// uint16_t day;
|
||||
// uint16_t month;
|
||||
// uint16_t year;
|
||||
// } adjusted_datetime;
|
||||
#define MAX(a,b) ({ typeof(a) _a = a; typeof(b) _b = b; _a > _b ? _a : _b; })
|
||||
#define MIN(a,b) ({ typeof(a) _a = a; typeof(b) _b = b; _a < _b ? _a : _b; })
|
||||
#define CLAMP(x, min, max) (MIN(MAX((x), (min)), (max)))
|
||||
|
||||
// static void save_adjusted_datetime () {
|
||||
#define YEAR_MIN 1996
|
||||
#define YEAR_MAX 2095
|
||||
|
||||
// }
|
||||
typedef enum {
|
||||
RTC_EDIT_YEAR,
|
||||
RTC_EDIT_MONTH,
|
||||
RTC_EDIT_DAY,
|
||||
RTC_EDIT_HOUR,
|
||||
RTC_EDIT_MIN,
|
||||
RTC_EDIT_SEC,
|
||||
} rtc_field_t;
|
||||
|
||||
static const char* const DAYS_OF_WEEK[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
|
||||
static struct tm rtc_tm = {0};
|
||||
static bool is_editing_mode;
|
||||
static rtc_field_t editing_field_type;
|
||||
|
||||
int wrap( uint16_t val, uint16_t min, uint16_t max ) {
|
||||
if( val < min ) return max;
|
||||
if( val > max ) return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
rtc_time_t rtc_time_from_tm( struct tm *time ) {
|
||||
return(rtc_time_t){
|
||||
.year = CLAMP(time->tm_year + 1900, YEAR_MIN, YEAR_MAX),
|
||||
.month = CLAMP(time->tm_mon, 1, 12),
|
||||
.day = CLAMP(time->tm_mday, 1, 31),
|
||||
.hour = CLAMP(time->tm_hour, 0, 23),
|
||||
.min = CLAMP(time->tm_min, 0, 59),
|
||||
.sec = CLAMP(time->tm_sec, 0, 59),
|
||||
.week_day = CLAMP(time->tm_wday, 0, 6),
|
||||
};
|
||||
}
|
||||
|
||||
void adjust_rtc_time( struct tm *t, int incr ) {
|
||||
switch(editing_field_type)
|
||||
{
|
||||
case RTC_EDIT_YEAR:
|
||||
t->tm_year = wrap( t->tm_year + incr, YEAR_MIN - 1900, YEAR_MAX - 1900 );
|
||||
break;
|
||||
case RTC_EDIT_MONTH:
|
||||
t->tm_mon = wrap( t->tm_mon + incr, 0, 11 );
|
||||
break;
|
||||
case RTC_EDIT_DAY:
|
||||
t->tm_mday = wrap( t->tm_mday + incr, 1, 31 );
|
||||
break;
|
||||
case RTC_EDIT_HOUR:
|
||||
t->tm_hour = wrap( t->tm_hour + incr, 0, 23 );
|
||||
break;
|
||||
case RTC_EDIT_MIN:
|
||||
t->tm_min = wrap( t->tm_min + incr, 0, 59 );
|
||||
break;
|
||||
case RTC_EDIT_SEC:
|
||||
t->tm_sec = wrap( t->tm_sec + incr, 0, 59 );
|
||||
break;
|
||||
}
|
||||
// Recalculate day-of-week and day-of-year
|
||||
time_t timestamp = mktime( t );
|
||||
*t = *gmtime( ×tamp );
|
||||
}
|
||||
|
||||
void component_editdatetime_draw ( struct tm t, rtc_field_t selected_field ) {
|
||||
// FIXME: move this to components.c once improved.
|
||||
/* Format RTC date/time as strings */
|
||||
char full_dt[30];
|
||||
char current_selection_chars[30];
|
||||
|
||||
snprintf( full_dt, sizeof(full_dt), ">%04d|%02d|%02d|%02d|%02d|%02d< %s",
|
||||
t.tm_year + 1900,
|
||||
t.tm_mon + 1,
|
||||
t.tm_mday,
|
||||
t.tm_hour,
|
||||
t.tm_min,
|
||||
t.tm_sec,
|
||||
DAYS_OF_WEEK[t.tm_wday]
|
||||
);
|
||||
|
||||
switch(selected_field)
|
||||
{
|
||||
// Note: for what ever reason, hat chars need to be duplicated to display correctly. This will be solved when there is a decent UI for it.
|
||||
case RTC_EDIT_YEAR:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "*^^^^^^^^********************");
|
||||
break;
|
||||
case RTC_EDIT_MONTH:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "******^^^^*****************");
|
||||
break;
|
||||
case RTC_EDIT_DAY:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "*********^^^^**************");
|
||||
break;
|
||||
case RTC_EDIT_HOUR:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "************^^^^***********");
|
||||
break;
|
||||
case RTC_EDIT_MIN:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "***************^^^^********");
|
||||
break;
|
||||
case RTC_EDIT_SEC:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "******************^^^^*****");
|
||||
break;
|
||||
}
|
||||
component_messagebox_draw(
|
||||
"|YYYY|MM|DD|HH|MM|SS| DOW\n%s\n%s\n", full_dt, current_selection_chars);
|
||||
}
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
if (menu->actions.back && !is_editing_mode) {
|
||||
sound_play_effect(SFX_EXIT);
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
}
|
||||
else if (menu->actions.enter && !is_editing_mode) {
|
||||
rtc_tm = *gmtime(&menu->current_time);
|
||||
is_editing_mode = true;
|
||||
}
|
||||
|
||||
if (is_editing_mode) {
|
||||
if (menu->actions.go_left) {
|
||||
if ( editing_field_type <= RTC_EDIT_YEAR ) { editing_field_type = RTC_EDIT_SEC; }
|
||||
else { editing_field_type = editing_field_type - 1; }
|
||||
}
|
||||
else if (menu->actions.go_right) {
|
||||
if ( editing_field_type >= RTC_EDIT_SEC ) { editing_field_type = RTC_EDIT_YEAR; }
|
||||
else { editing_field_type = editing_field_type + 1; }
|
||||
}
|
||||
else if (menu->actions.go_up) {
|
||||
adjust_rtc_time( &rtc_tm, +1 );
|
||||
}
|
||||
else if (menu->actions.go_down) {
|
||||
adjust_rtc_time( &rtc_tm, -1 );
|
||||
}
|
||||
else if (menu->actions.options) { // R button = save
|
||||
if(rtc_is_writable()) {
|
||||
// FIXME: settimeofday is not available in libdragon yet.
|
||||
// struct timeval new_time = { .tv_sec = mktime(&rtc_tm) };
|
||||
// int res = settimeofday(&new_time, NULL);
|
||||
|
||||
rtc_time_t rtc_time = rtc_time_from_tm(&rtc_tm);
|
||||
int res = rtc_set(&rtc_time);
|
||||
if (res != 1) {
|
||||
menu_show_error(menu, "Failed to set RTC time");
|
||||
}
|
||||
}
|
||||
else {
|
||||
menu_show_error(menu, "RTC is not writable");
|
||||
}
|
||||
is_editing_mode = false;
|
||||
}
|
||||
else if (menu->actions.back) { // cancel
|
||||
is_editing_mode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void draw (menu_t *menu, surface_t *d) {
|
||||
@ -30,36 +169,51 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_layout_draw();
|
||||
|
||||
component_main_text_draw(
|
||||
component_main_text_draw(
|
||||
ALIGN_CENTER, VALIGN_TOP,
|
||||
"ADJUST REAL TIME CLOCK\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"To set the date and time, please use the PC terminal\n"
|
||||
"application and set via USB,\n or a N64 game with RTC support.\n\n"
|
||||
"Current date & time: %s\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n"
|
||||
);
|
||||
|
||||
component_main_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
"To set the RTC date and time, Press A.\n"
|
||||
"You can also use the PC terminal application via USB,\n"
|
||||
"or even an N64 game with RTC support.\n"
|
||||
"\n"
|
||||
"Current date & time: %s\n"
|
||||
"\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown"
|
||||
);
|
||||
|
||||
if (!is_editing_mode) {
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"A: Change\n"
|
||||
"B: Back"
|
||||
);
|
||||
}
|
||||
else {
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_RIGHT, VALIGN_TOP,
|
||||
"Up/Down: Adjust Field\n"
|
||||
"Left/Right: Switch Field"
|
||||
);
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"R: Save\n"
|
||||
"B: Back"
|
||||
);
|
||||
}
|
||||
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n" // "A: Save\n"
|
||||
"B: Back"
|
||||
);
|
||||
if (is_editing_mode) {
|
||||
component_editdatetime_draw(rtc_tm, editing_field_type);
|
||||
}
|
||||
|
||||
rdpq_detach_show();
|
||||
}
|
||||
|
||||
|
||||
void view_rtc_init (menu_t *menu) {
|
||||
// Nothing to initialize (yet)
|
||||
is_editing_mode = false;
|
||||
editing_field_type = RTC_EDIT_YEAR;
|
||||
}
|
||||
|
||||
void view_rtc_display (menu_t *menu, surface_t *display) {
|
||||
|
@ -57,7 +57,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
"Joypad 2 is %sconnected %s\n"
|
||||
"Joypad 3 is %sconnected %s\n"
|
||||
"Joypad 4 is %sconnected %s\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown",
|
||||
is_memory_expanded() ? "" : "not ",
|
||||
(joypad[0]) ? "" : "not ", format_accessory(0),
|
||||
(joypad[1]) ? "" : "not ", format_accessory(1),
|
||||
|
Loading…
Reference in New Issue
Block a user