diff --git a/include/gint/gint.h b/include/gint/gint.h index 3f65ce5..f6f89b4 100644 --- a/include/gint/gint.h +++ b/include/gint/gint.h @@ -80,6 +80,14 @@ void gint_osmenu_native(void); @restart 0 to exit, 1 to restart by using gint_osmenu() */ void gint_setrestart(int restart); +/* gint_poweroff(): World switch and power off the calculator + Shows the CASIO logo / poweroff screen if show_logo is true. The program + will resume execution normally after powering on again. Don't call this + function with show_logo=false as a result of pressing AC/ON because the + calculator will restart immediately unless the user releases the AC/ON key + extremely quickly. */ +void gint_poweroff(bool show_logo); + /* gint_set_onchip_save_mode(): Specify memory save policy for world switches World switches can cause corruption in on-chip memory in two ways. First, if diff --git a/include/gint/keyboard.h b/include/gint/keyboard.h index 1289991..73fb87d 100644 --- a/include/gint/keyboard.h +++ b/include/gint/keyboard.h @@ -258,11 +258,13 @@ enum { GETKEY_MENU_DUPDATE = 0x0100, /* After coming back from the main menu, send a KEYEV_OSMENU event */ GETKEY_MENU_EVENT = 0x0200, + /* Enable power off with SHIFT + AC/ON */ + GETKEY_POWEROFF = 0x0400, /* No modifiers */ GETKEY_NONE = 0x0000, /* Default settings of getkey() */ - GETKEY_DEFAULT = 0x01df, + GETKEY_DEFAULT = 0x05df, }; /* getkey_feature_t: Custom feature function diff --git a/src/kernel/kernel.h b/src/kernel/kernel.h index a136c9a..3efc8cb 100644 --- a/src/kernel/kernel.h +++ b/src/kernel/kernel.h @@ -8,6 +8,10 @@ /* gint_load_onchip_sections(): Initialize on-chip memory sections */ void gint_load_onchip_sections(void); +/* gint_copy_vram(): Copy gint's VRAM to the OS to avoid flickering during + certain world switches. */ +void gint_copy_vram(void); + /* kinit(): Install and start gint */ void kinit(void); diff --git a/src/kernel/osmenu.c b/src/kernel/osmenu.c index bd1351f..a98a721 100644 --- a/src/kernel/osmenu.c +++ b/src/kernel/osmenu.c @@ -2,6 +2,7 @@ #include #include #include +#include "kernel.h" #include @@ -12,7 +13,6 @@ int __Timer_Deinstall(int id); int __PutKeyCode(int row, int column, int keycode); int __GetKeyWait(int *col,int *row,int type,int time,int menu,uint16_t *key); void __ClearKeyBuffer(void); /* ? */ -void *__GetVRAMAddress(void); void __ConfigureStatusArea(int mode); void __SetQuitHandler(void (*callback)(void)); @@ -95,28 +95,12 @@ static os_menu_function_t *find_os_menu_function(void) void gint_osmenu_native(void) { __ClearKeyBuffer(); - - #ifdef FX9860G - memcpy(__GetVRAMAddress(), gint_vram, 1024); - #endif + gint_copy_vram(); #ifdef FXCG50 /* Unfortunately ineffective (main menu probably reenables it) __ConfigureStatusArea(3); */ - /* TODO: Improve copied VRAM behavior in gint_osmenu() on fxcg50 */ - uint16_t *vram1, *vram2; - dgetvram(&vram1, &vram2); - - uint16_t *dst = __GetVRAMAddress(); - uint16_t *src = (gint_vram == vram1) ? vram2 + 6 : vram1 + 6; - - for(int y = 0; y < 216; y++, dst+=384, src+=396) - for(int x = 0; x < 384; x++) - { - dst[x] = src[x]; - } - /* Try to use the internal function directly if we could figure out its address by dynamically disassembling */ os_menu_function_t *fun = find_os_menu_function(); diff --git a/src/kernel/syscalls.S b/src/kernel/syscalls.S index f089cb7..cb7a58d 100644 --- a/src/kernel/syscalls.S +++ b/src/kernel/syscalls.S @@ -45,6 +45,7 @@ .global ___SetQuitHandler /* Reset */ +.global ___PowerOff .global ___Reset #define syscall_(id, syscall_table) \ @@ -120,6 +121,8 @@ ___SetQuitHandler: /* Reset */ +___PowerOff: + syscall(0x3f4) ___Reset: syscall(0x236) @@ -198,6 +201,8 @@ ___SpecialMatrixCodeProcessing: /* Reset */ +___PowerOff: + syscall(0x1839) ___Reset: syscall(0x1187) diff --git a/src/kernel/world.c b/src/kernel/world.c index 4b006ff..aed10b2 100644 --- a/src/kernel/world.c +++ b/src/kernel/world.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "kernel.h" #include @@ -214,3 +215,34 @@ int gint_get_onchip_save_mode(void **ptr) *ptr = onchip_save_buffer; return onchip_save_mode; } + +void gint_copy_vram(void) +{ + void *__GetVRAMAddress(void); + + #ifdef FX9860G + memcpy(__GetVRAMAddress(), gint_vram, 1024); + #endif + + #ifdef FXCG50 + /* TODO: Improve copied VRAM behavior in gint_osmenu() on fxcg50 */ + uint16_t *vram1, *vram2; + dgetvram(&vram1, &vram2); + + uint16_t *dst = __GetVRAMAddress(); + uint16_t *src = (gint_vram == vram1) ? vram2 + 6 : vram1 + 6; + + for(int y = 0; y < 216; y++, dst+=384, src+=396) + for(int x = 0; x < 384; x++) + { + dst[x] = src[x]; + } + #endif +} + +void gint_poweroff(bool show_logo) +{ + void __PowerOff(int show_logo); + gint_copy_vram(); + gint_world_switch(GINT_CALL(__PowerOff, (int)show_logo)); +} diff --git a/src/keysc/getkey.c b/src/keysc/getkey.c index 421dc12..0aa16fd 100644 --- a/src/keysc/getkey.c +++ b/src/keysc/getkey.c @@ -75,6 +75,16 @@ key_event_t getkey_opt(int opt, volatile int *timeout) e.type = KEYEV_OSMENU; } + /* Poweroff */ + if((opt & GETKEY_POWEROFF) && e.type == KEYEV_DOWN && + e.key == KEY_ACON && e.shift && !e.alpha) + { + gint_poweroff(true); + if(opt & GETKEY_MENU_DUPDATE) + dupdate(); + continue; + } + if(e.type != KEYEV_NONE || e.type != KEYEV_UP) { /* Custom global features */