RTC tests using a small clock application
This commit is contained in:
parent
99c1bf0dbf
commit
8f11ccce56
Binary file not shown.
After Width: | Height: | Size: 147 B |
Binary file not shown.
After Width: | Height: | Size: 641 B |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 147 B |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -29,6 +29,9 @@ void gintctl_gint_timer(void);
|
|||
/* gintctl_gint_timer_callbacks(): Stunts in the environment of callbacks */
|
||||
void gintctl_gint_timer_callbacks(void);
|
||||
|
||||
/* gintctl_gint_rtc(): Configure RTC and check timer speed */
|
||||
void gintctl_gint_rtc(void);
|
||||
|
||||
/* gintctl_gint_bopti(): Test image rendering */
|
||||
void gintctl_gint_bopti(void);
|
||||
|
||||
|
|
|
@ -0,0 +1,572 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/rtc.h>
|
||||
#include <gint/timer.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/std/stdio.h>
|
||||
|
||||
#include <gintctl/gint.h>
|
||||
#include <gintctl/util.h>
|
||||
|
||||
//---
|
||||
// Date and time display
|
||||
//---
|
||||
|
||||
extern bopti_image_t img_rtc_segments;
|
||||
|
||||
#ifdef FX9860G
|
||||
char const *days[7] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
char const *months[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
|
||||
"Nov", "Dec"
|
||||
};
|
||||
|
||||
/* Starting x,y and width of each segment image */
|
||||
static int x0=20, y0=8, dx=13;
|
||||
/* Starting x and y of date, and alternative y when editing */
|
||||
static int yd=36, eyd=12;
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
char const *days[7] = {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
|
||||
"Saturday"
|
||||
};
|
||||
char const *months[12] = {
|
||||
"January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"
|
||||
};
|
||||
|
||||
static int x0=89, y0=58, dx=32;
|
||||
static int yd=121, eyd=121;
|
||||
#endif
|
||||
|
||||
static void draw_time(rtc_time_t *time, int edit_field)
|
||||
{
|
||||
/* Height of characters */
|
||||
int sh = img_rtc_segments.height;
|
||||
/* Width of colon separator */
|
||||
int cw = img_rtc_segments.width - 10 * dx;
|
||||
|
||||
int digits[6] = {
|
||||
time->hours / 10,
|
||||
time->hours % 10,
|
||||
time->minutes / 10,
|
||||
time->minutes % 10,
|
||||
time->seconds / 10,
|
||||
time->seconds % 10,
|
||||
};
|
||||
|
||||
for(int i=0, x=x0; i < 6; i++)
|
||||
{
|
||||
dsubimage(x, y0, &img_rtc_segments, dx*digits[i], 0, dx, sh,
|
||||
DIMAGE_NONE);
|
||||
|
||||
x += dx;
|
||||
|
||||
if(i != 1 && i != 3) continue;
|
||||
dsubimage(x, y0, &img_rtc_segments, 10*dx,0,cw,sh, DIMAGE_NONE);
|
||||
x += cw;
|
||||
}
|
||||
|
||||
if(edit_field >= 0)
|
||||
{
|
||||
int x = x0 + (2 * dx + cw) * edit_field - 1;
|
||||
int y = y0 - 1;
|
||||
|
||||
#ifdef FX9860G
|
||||
drect(x, y, x + 2*dx - 1, y + sh+1, C_INVERT);
|
||||
|
||||
row_print(6, 1, "EXE: Set time");
|
||||
row_print(7, 1, "EXIT: Cancel");
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
for(int a = y - 1; a <= y + sh + 2; a++)
|
||||
for(int b = x - 1; b <= x + 2*dx - 2; b++)
|
||||
{
|
||||
gint_vram[396*a+b] ^= 0xffff;
|
||||
}
|
||||
|
||||
row_print(12, 1, "EXE: Set time");
|
||||
row_print(13, 1, "EXIT: Cancel");
|
||||
#endif
|
||||
|
||||
extern bopti_image_t img_rtc_arrows;
|
||||
int xa = x0 + (2 * dx + cw) * edit_field + dx - 4;
|
||||
int ya1 = y - _(1,3) - img_rtc_arrows.height;
|
||||
int ya2 = y0 + sh + _(2,4);
|
||||
dsubimage(xa, ya1, &img_rtc_arrows, 0,0,7,4, DIMAGE_NONE);
|
||||
dsubimage(xa, ya2, &img_rtc_arrows, 8,0,7,4, DIMAGE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_date(rtc_time_t *time, int edit_field)
|
||||
{
|
||||
int w[4], h, space_width;
|
||||
char month_day[16];
|
||||
char year[16];
|
||||
|
||||
sprintf(month_day, "%02d", time->month_day);
|
||||
sprintf(year, "%4d", time->year);
|
||||
|
||||
dsize(" ", NULL, &space_width, NULL);
|
||||
dsize(days[time->week_day], NULL, &w[0], &h);
|
||||
dsize(months[time->month], NULL, &w[1], &h);
|
||||
dsize(month_day, NULL, &w[2], &h);
|
||||
dsize(year, NULL, &w[3], &h);
|
||||
|
||||
int y = (edit_field >= 0) ? eyd: yd;
|
||||
int xd = (DWIDTH - (w[0]+w[1]+w[2]+w[3] + 3 * (space_width + 2))) / 2;
|
||||
|
||||
dprint(xd, y, C_BLACK, "%s %s %s %s", days[time->week_day],
|
||||
months[time->month], month_day, year);
|
||||
|
||||
if(edit_field >= 0)
|
||||
{
|
||||
int x = 0;
|
||||
for(int i = 0; i < edit_field; i++)
|
||||
x += w[i] + space_width + 2;
|
||||
|
||||
#ifdef FX9860G
|
||||
drect(xd+x-1, y-1, xd+x+w[edit_field], y+h, C_INVERT);
|
||||
|
||||
row_print(6, 1, "EXE: Set date");
|
||||
row_print(7, 1, "EXIT: Cancel");
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
for(int a = y-2; a <= y+h; a++)
|
||||
for(int b = xd+x-2; b <= xd+x+w[edit_field]+1; b++)
|
||||
{
|
||||
gint_vram[396*a+b] ^= 0xffff;
|
||||
}
|
||||
|
||||
row_print(12, 1, "EXE: Set date");
|
||||
row_print(13, 1, "EXIT: Cancel");
|
||||
#endif
|
||||
|
||||
extern bopti_image_t img_rtc_arrows;
|
||||
int xa = xd + x - 3 + (w[edit_field] >> 1);
|
||||
int ya1 = y - _(2,4) - img_rtc_arrows.height;
|
||||
int ya2 = y + h + _(2,3);
|
||||
dsubimage(xa, ya1, &img_rtc_arrows, 0,0,7,4, DIMAGE_NONE);
|
||||
dsubimage(xa, ya2, &img_rtc_arrows, 8,0,7,4, DIMAGE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_rtc(rtc_time_t *time)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
draw_time(time, -1);
|
||||
draw_date(time, -1);
|
||||
|
||||
#ifdef FX9860G
|
||||
extern bopti_image_t img_opt_gint_rtc;
|
||||
dsubimage(0, 56, &img_opt_gint_rtc, 0, 0, 128, 8, DIMAGE_NONE);
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
row_title("Real-Time Clock");
|
||||
fkey_menu(1, "RTC");
|
||||
fkey_menu(2, "TIMER");
|
||||
fkey_action(5, "DATE");
|
||||
fkey_action(6, "TIME");
|
||||
#endif
|
||||
|
||||
dupdate();
|
||||
}
|
||||
|
||||
//---
|
||||
// Speed comparison of RTC and timers
|
||||
//---
|
||||
|
||||
static void draw_speed(rtc_time_t *time)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
|
||||
#ifdef FX9860G
|
||||
extern bopti_image_t img_opt_gint_rtc;
|
||||
row_print(1, 1, "Speed of RTC vs TMU");
|
||||
dsubimage(0, 56, &img_opt_gint_rtc, 0, 9, 128, 8, DIMAGE_NONE);
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
row_title("Speed comparison of RTC and timers");
|
||||
fkey_menu(1, "RTC");
|
||||
fkey_menu(2, "TIMER");
|
||||
#endif
|
||||
|
||||
dprint_opt(DWIDTH-2, DHEIGHT-1, C_BLACK, C_NONE, DTEXT_RIGHT,
|
||||
DTEXT_BOTTOM, "%s %d, %02d:%02d", months[time->month],
|
||||
time->month_day, time->hours, time->minutes);
|
||||
dupdate();
|
||||
}
|
||||
|
||||
//---
|
||||
// Edition facilities
|
||||
//---
|
||||
|
||||
static int days_in_month(rtc_time_t *time)
|
||||
{
|
||||
int base[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
if(time->month != 1) return base[time->month];
|
||||
|
||||
int leap_year = 0;
|
||||
if(time->year % 4 == 0) leap_year = 1;
|
||||
if(time->year % 100 == 0) leap_year = 0;
|
||||
if(time->year % 400 == 0) leap_year = 1;
|
||||
return base[time->month] + leap_year;
|
||||
}
|
||||
|
||||
static void normalize(rtc_time_t *time)
|
||||
{
|
||||
/* Check that month_day is still valid */
|
||||
int max = days_in_month(time);
|
||||
if(time->month_day > max) time->month_day = max;
|
||||
}
|
||||
|
||||
static void move_field(rtc_time_t *time, int field, int diff)
|
||||
{
|
||||
if(field == 0) time->hours = (time->hours + 24 + diff) % 24;
|
||||
if(field == 1) time->minutes = (time->minutes + 60 + diff) % 60;
|
||||
if(field == 2) time->seconds = (time->seconds + 60 + diff) % 60;
|
||||
if(field == 3) time->week_day = (time->week_day + 7 + diff) % 7;
|
||||
|
||||
if(field == 4)
|
||||
{
|
||||
time->month = (time->month + 12 + diff) % 12;
|
||||
normalize(time);
|
||||
}
|
||||
if(field == 5)
|
||||
{
|
||||
int max = days_in_month(time);
|
||||
time->month_day = ((time->month_day-1) + max + diff) % max + 1;
|
||||
}
|
||||
if(field == 6)
|
||||
{
|
||||
time->year += diff;
|
||||
if(diff < 0 && -diff > time->year) time->year = 0;
|
||||
if(time->year > 9999) time->year = 9999;
|
||||
normalize(time);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_field(rtc_time_t *time, int field, int value)
|
||||
{
|
||||
if(field == 0) time->hours = value;
|
||||
if(field == 1) time->minutes = value;
|
||||
if(field == 2) time->seconds = value;
|
||||
if(field == 3) time->week_day = value;
|
||||
if(field == 4) time->month = value;
|
||||
if(field == 5) time->month_day = value;
|
||||
if(field == 6) time->year = value;
|
||||
}
|
||||
|
||||
static int valid_field(rtc_time_t *time, int field, int value)
|
||||
{
|
||||
if(field == 0)
|
||||
return value >= 0 && value < 24;
|
||||
if(field == 1 || field == 2)
|
||||
return value >= 0 && value < 60;
|
||||
if(field == 3)
|
||||
return value >= 0 && value < 7;
|
||||
if(field == 4)
|
||||
return value >= 0 && value < 12;
|
||||
if(field == 5)
|
||||
return value >= 1 && value <= days_in_month(time);
|
||||
if(field == 6)
|
||||
return value >= 0 && value <= 9999;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void edit_time(void)
|
||||
{
|
||||
int key=0, edit_field=0;
|
||||
rtc_time_t time;
|
||||
rtc_get_time(&time);
|
||||
|
||||
int key_input = 0;
|
||||
int key_sequence = 0;
|
||||
|
||||
while(key != KEY_EXE && key != KEY_EXIT)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
draw_time(&time, edit_field);
|
||||
#ifdef FXCG50
|
||||
draw_date(&time, -1);
|
||||
row_title("Real-Time Clock");
|
||||
#endif
|
||||
dupdate();
|
||||
|
||||
key = getkey().key;
|
||||
|
||||
if(keycode_digit(key) >= 0)
|
||||
{
|
||||
/* Try to append the digit to the current value, if it
|
||||
gives an invalid value restart the input sequence */
|
||||
key_input = key_input * 10 + keycode_digit(key);
|
||||
key_sequence++;
|
||||
|
||||
if(!valid_field(&time, edit_field, key_input))
|
||||
{
|
||||
key_input = keycode_digit(key);
|
||||
key_sequence = 1;
|
||||
}
|
||||
|
||||
set_field(&time, edit_field, key_input);
|
||||
|
||||
/* If a field is fully set, switch to the next one */
|
||||
if(key_sequence == 2)
|
||||
{
|
||||
if(edit_field == 2)
|
||||
{
|
||||
key = KEY_EXE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
edit_field++;
|
||||
key_input = 0;
|
||||
key_sequence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Any key other than a digit breaks an input sequence */
|
||||
key_input = 0;
|
||||
key_sequence = 0;
|
||||
|
||||
if(key == KEY_LEFT && edit_field > 0) edit_field--;
|
||||
if(key == KEY_RIGHT && edit_field < 2) edit_field++;
|
||||
|
||||
if(key == KEY_UP) move_field(&time, edit_field, +1);
|
||||
if(key == KEY_DOWN) move_field(&time, edit_field, -1);
|
||||
}
|
||||
|
||||
if(key == KEY_EXE) rtc_set_time(&time);
|
||||
}
|
||||
|
||||
static void edit_date(void)
|
||||
{
|
||||
int key=0, edit_field=0, option_tab=0;
|
||||
rtc_time_t time;
|
||||
rtc_get_time(&time);
|
||||
|
||||
int key_input = 0;
|
||||
int key_sequence = 0;
|
||||
|
||||
while(key != KEY_EXE && key != KEY_EXIT)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
#ifdef FXCG50
|
||||
draw_time(&time, -1);
|
||||
row_title("Real-Time Clock");
|
||||
#endif
|
||||
draw_date(&time, edit_field);
|
||||
|
||||
#ifdef FX9860G
|
||||
extern bopti_image_t img_opt_gint_rtc;
|
||||
if(edit_field == 0)
|
||||
dsubimage(0, 56, &img_opt_gint_rtc, 0, option_tab*9+18,
|
||||
128, 8, DIMAGE_NONE);
|
||||
if(edit_field == 1)
|
||||
dsubimage(0, 56, &img_opt_gint_rtc, 0, option_tab*9+36,
|
||||
128, 8, DIMAGE_NONE);
|
||||
#endif
|
||||
|
||||
#ifdef FXCG50
|
||||
char const *fkey_days[] = {
|
||||
"SUN", "MON", "TUE", "WED", "THUR", "FRI", "SAT"
|
||||
};
|
||||
if(edit_field == 0) for(int i = 0; i < 5; i++)
|
||||
{
|
||||
int id = 5 * option_tab + i;
|
||||
if(id < 7) fkey_menu(i+1, fkey_days[id]);
|
||||
}
|
||||
|
||||
char const *fkey_months[] = {
|
||||
"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG",
|
||||
"SEP", "OCT", "NOV", "DEC"
|
||||
};
|
||||
if(edit_field == 1) for(int i = 0; i < 5; i++)
|
||||
{
|
||||
int id = 5 * option_tab + i;
|
||||
if(id < 12) fkey_menu(i+1, fkey_months[id]);
|
||||
}
|
||||
|
||||
if(edit_field < 2) fkey_action(6, ">");
|
||||
#endif
|
||||
|
||||
dupdate();
|
||||
key = getkey().key;
|
||||
|
||||
if(keycode_digit(key) >= 0 && edit_field >= 2)
|
||||
{
|
||||
/* Try to append the digit to the current value, if it
|
||||
gives an invalid value restart the input sequence */
|
||||
key_input = key_input * 10 + keycode_digit(key);
|
||||
key_sequence++;
|
||||
|
||||
if(!valid_field(&time, edit_field+3, key_input))
|
||||
{
|
||||
key_input = keycode_digit(key);
|
||||
key_sequence = 1;
|
||||
}
|
||||
|
||||
set_field(&time, edit_field+3, key_input);
|
||||
|
||||
/* If a field is fully set, switch to the next one */
|
||||
if((edit_field == 2 && key_sequence == 2)
|
||||
|| (edit_field == 3 && key_sequence == 4))
|
||||
{
|
||||
if(edit_field == 3)
|
||||
{
|
||||
key = KEY_EXE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
edit_field++;
|
||||
option_tab = 0;
|
||||
key_input = 0;
|
||||
key_sequence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Any key other than a digit breaks an input sequence */
|
||||
key_input = 0;
|
||||
key_sequence = 0;
|
||||
|
||||
if(key == KEY_LEFT && edit_field > 0)
|
||||
{
|
||||
edit_field--;
|
||||
option_tab = 0;
|
||||
}
|
||||
if(key == KEY_RIGHT && edit_field < 3)
|
||||
{
|
||||
edit_field++;
|
||||
option_tab = 0;
|
||||
}
|
||||
|
||||
int fk = keycode_function(key);
|
||||
if(fk >= 1 && fk <= 5)
|
||||
{
|
||||
int value = option_tab * 5 + fk - 1;
|
||||
if(valid_field(&time, edit_field+3, value))
|
||||
{
|
||||
set_field(&time, edit_field+3, value);
|
||||
|
||||
/* Go to next field */
|
||||
if(edit_field == 3)
|
||||
{
|
||||
key = KEY_EXE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
edit_field++;
|
||||
option_tab = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(key == KEY_F6)
|
||||
{
|
||||
int max = (edit_field == 0) ? 1 : 2;
|
||||
option_tab++;
|
||||
if(option_tab > max) option_tab = 0;
|
||||
}
|
||||
|
||||
if(key == KEY_UP) move_field(&time, edit_field+3, +1);
|
||||
if(key == KEY_DOWN) move_field(&time, edit_field+3, -1);
|
||||
}
|
||||
|
||||
if(key == KEY_EXE)
|
||||
{
|
||||
/* Copy current time and set only the date */
|
||||
int wd = time.week_day;
|
||||
int d = time.month_day;
|
||||
int m = time.month;
|
||||
int y = time.year;
|
||||
|
||||
rtc_get_time(&time);
|
||||
time.week_day = wd;
|
||||
time.month_day = d;
|
||||
time.month = m;
|
||||
time.year = y;
|
||||
rtc_set_time(&time);
|
||||
}
|
||||
}
|
||||
|
||||
//---
|
||||
// Main screen with lazy update
|
||||
//---
|
||||
|
||||
static volatile int frame_done = 0;
|
||||
|
||||
static int rtc_timer_callback(void)
|
||||
{
|
||||
frame_done = 0;
|
||||
return TIMER_CONTINUE;
|
||||
}
|
||||
|
||||
/* gintctl_gint_rtc(): Configure RTC and check timer speed */
|
||||
void gintctl_gint_rtc(void)
|
||||
{
|
||||
key_event_t ev;
|
||||
rtc_time_t time;
|
||||
|
||||
int run_loop = 1;
|
||||
int tab = 1;
|
||||
|
||||
rtc_start_timer(RTC_1Hz, rtc_timer_callback);
|
||||
|
||||
while(run_loop)
|
||||
{
|
||||
if(!frame_done) rtc_get_time(&time);
|
||||
|
||||
/* Redraw only when a second elapses */
|
||||
if(!frame_done && tab == 1)
|
||||
{
|
||||
draw_rtc(&time);
|
||||
frame_done = 1;
|
||||
}
|
||||
else if(!frame_done && tab == 2)
|
||||
{
|
||||
draw_speed(&time);
|
||||
frame_done = 1;
|
||||
}
|
||||
|
||||
/* Handle keyboard events */
|
||||
while((ev = pollevent()).type != KEYEV_NONE)
|
||||
{
|
||||
if(ev.type != KEYEV_DOWN) continue;
|
||||
int action = 1;
|
||||
|
||||
if(ev.key == KEY_EXIT) run_loop = 0;
|
||||
else if(ev.key == KEY_MENU) gint_osmenu();
|
||||
else if(ev.key == KEY_F1) tab = 1;
|
||||
else if(ev.key == KEY_F2) tab = 2;
|
||||
else if(ev.key == KEY_F5 && tab == 1) edit_date();
|
||||
else if(ev.key == KEY_F6 && tab == 1) edit_time();
|
||||
else action = 0;
|
||||
|
||||
if(action) frame_done = 0;
|
||||
}
|
||||
|
||||
/* Wait for either keyboard or RTC to produce an event, except
|
||||
if we already have work to do */
|
||||
if(frame_done) sleep();
|
||||
}
|
||||
|
||||
rtc_stop_timer();
|
||||
}
|
|
@ -46,7 +46,7 @@ struct menu menu_gint = {
|
|||
#ifdef FXCG50
|
||||
{ "DMA Control", gintctl_gint_dma },
|
||||
#endif
|
||||
{ "Real-time clock", NULL },
|
||||
{ "Real-time clock", gintctl_gint_rtc },
|
||||
{ "Image rendering", gintctl_gint_bopti },
|
||||
{ "Text rendering", gintctl_gint_topti },
|
||||
#ifdef FX9860G
|
||||
|
|
Loading…
Reference in New Issue