diff --git a/include/overlay026/ov26_02256404.h b/include/overlay026/ov26_02256404.h deleted file mode 100644 index df7d704f6a..0000000000 --- a/include/overlay026/ov26_02256404.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef POKEPLATINUM_OV26_02256404_H -#define POKEPLATINUM_OV26_02256404_H - -#include "overlay026/struct_ov26_02256404_1.h" -#include "overlay026/struct_ov26_02256404_decl.h" - -#include "bg_window.h" - -BOOL ov26_02256404(UnkStruct_ov26_02256404 **param0, const UnkStruct_ov26_02256404_1 *param1, BgConfig *param2); -void ov26_0225649C(UnkStruct_ov26_02256404 *param0); -void ov26_022564A8(UnkStruct_ov26_02256404 *param0, u32 param1); -BOOL ov26_022564CC(UnkStruct_ov26_02256404 *param0, u32 param1); -BOOL ov26_022564D8(UnkStruct_ov26_02256404 *param0); - -#endif // POKEPLATINUM_OV26_02256404_H diff --git a/include/overlay026/struct_ov26_02256404_1.h b/include/overlay026/struct_ov26_02256404_1.h deleted file mode 100644 index 1b35341c26..0000000000 --- a/include/overlay026/struct_ov26_02256404_1.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef POKEPLATINUM_STRUCT_OV26_02256404_1_H -#define POKEPLATINUM_STRUCT_OV26_02256404_1_H - -#include - -typedef struct { - RTCTime unk_00; - u32 unk_0C; -} UnkStruct_ov26_02256404_1; - -#endif // POKEPLATINUM_STRUCT_OV26_02256404_1_H diff --git a/include/overlay026/struct_ov26_02256404_decl.h b/include/overlay026/struct_ov26_02256404_decl.h deleted file mode 100644 index 4491620a73..0000000000 --- a/include/overlay026/struct_ov26_02256404_decl.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef POKEPLATINUM_STRUCT_OV26_02256404_DECL_H -#define POKEPLATINUM_STRUCT_OV26_02256404_DECL_H - -typedef struct UnkStruct_ov26_02256404_t UnkStruct_ov26_02256404; - -#endif // POKEPLATINUM_STRUCT_OV26_02256404_DECL_H diff --git a/include/poketch_digital_watch/display.h b/include/poketch_digital_watch/display.h new file mode 100644 index 0000000000..9d6b7ce292 --- /dev/null +++ b/include/poketch_digital_watch/display.h @@ -0,0 +1,50 @@ +#ifndef POKEPLATINUM_POKETCH_DIGITAL_WATCH_DISPLAY_H +#define POKEPLATINUM_POKETCH_DIGITAL_WATCH_DISPLAY_H + +#include "bg_window.h" + +// Display Tasks +#define NUM_TASK_SLOTS 8 + +#define DISPLAY_TASK_SETUP_BACKGROUND 0 +#define DISPLAY_TASK_UPDATE_WATCH_DIGITS 1 +#define DISPLAY_TASK_TOGGLE_BACKLIGHT 2 +#define DISPLAY_TASK_FREE_BACKGROUND 3 + +// Graphics +#define POKETCH_DIGITAL_WATCH_NARC_TILES_IDX 23 +#define POKETCH_DIGITAL_WATCH_NARC_TILEMAP_IDX 24 +#define POKETCH_CLOCK_DIGITS_TILEMAP_IDX 25 +#define POKETCH_NUM_CLOCK_DIGITS 10 + +#define POKETCH_CLOCK_DIGIT_WIDTH 4 +#define POKETCH_CLOCK_DIGIT_HEIGHT 9 +#define POKETCH_CLOCK_DIGIT_GAP 1 +#define POKETCH_CLOCK_HOURS_DIGIT_X 3 +#define POKETCH_CLOCK_HOURS_DIGIT_Y 7 +#define POKETCH_CLOCK_MINUTES_DIGIT_X 15 +#define POKETCH_CLOCK_MINUTES_DIGIT_Y 7 + +#define POKETCH_DIGIT_TILEMAP_WIDTH (POKETCH_CLOCK_DIGIT_WIDTH * POKETCH_NUM_CLOCK_DIGITS) +#define POKETCH_DIGIT_TILEMAP_HEIGHT (POKETCH_CLOCK_DIGIT_HEIGHT) +#define POKETCH_DIGIT_TILEMAP_SIZE_BYTES (POKETCH_DIGIT_TILEMAP_WIDTH * POKETCH_DIGIT_TILEMAP_HEIGHT) + +typedef struct { + RTCTime time; + u32 backlightActive; +} WatchData; + +typedef struct DisplayManager { + const WatchData *watchData; + BgConfig *bgConfig; + u32 taskList[2 + NUM_TASK_SLOTS]; + u16 digitsTilemap[POKETCH_DIGIT_TILEMAP_SIZE_BYTES]; +} DisplayManager; + +BOOL PoketchDigitalWatch_SetupDisplayManager(DisplayManager **displayManager, const WatchData *watchData, BgConfig *bgConfig); +void PoketchDigitalWatch_FreeDisplayManager(DisplayManager *displayManager); +void PoketchDigitalWatch_StartDisplayTask(DisplayManager *displayManager, u32 taskID); +BOOL PoketchDigitalWatch_DisplayTaskIsNotActive(DisplayManager *displayManager, u32 taskID); +BOOL PoketchDigitalWatch_NoActiveDisplayTasks(DisplayManager *displayManager); + +#endif // POKEPLATINUM_POKETCH_DIGITAL_WATCH_DISPLAY_H diff --git a/platinum.us/main.lsf b/platinum.us/main.lsf index 6531a18134..d80e7e924f 100644 --- a/platinum.us/main.lsf +++ b/platinum.us/main.lsf @@ -878,11 +878,11 @@ Overlay overlay25 Object main.nef.p/src_overlay025_ov25_02255DBC.c.o } -Overlay overlay26 +Overlay poketch_digital_watch { After overlay25 - Object main.nef.p/src_overlay026_ov26_022561C0.c.o - Object main.nef.p/src_overlay026_ov26_02256404.c.o + Object main.nef.p/src_poketch_digital_watch_main.c.o + Object main.nef.p/src_poketch_digital_watch_display.c.o } Overlay overlay27 diff --git a/platinum.us/sbins.sha1 b/platinum.us/sbins.sha1 index bc9ecdd0f2..b0892b063c 100644 --- a/platinum.us/sbins.sha1 +++ b/platinum.us/sbins.sha1 @@ -25,7 +25,7 @@ d414d37a9b80f1d346666ad9ef5ba635d5ebb552 *overlay19.sbin 2e8fcd133e2736d90dae6e23ac9a669cefc1a7c8 *overlay23.sbin cc4bb361071632627532c48af9a0b37c1751670a *pre_poketch_subscreen.sbin 0fbd0432432d42462b9c02f07e30634987708dc6 *overlay25.sbin -44e45c2b6ec6aa74142550f25f770954b8e0d555 *overlay26.sbin +44e45c2b6ec6aa74142550f25f770954b8e0d555 *poketch_digital_watch.sbin 3301af166bc328d4df4412dbf6c740635151867c *overlay27.sbin 98a048c770a311a3fd756ad725997964fdd14aa8 *overlay28.sbin ca63341e12e782896fc58d5ce6fefa2170b5e921 *overlay29.sbin diff --git a/src/meson.build b/src/meson.build index 9060c05795..d378035f2a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -667,8 +667,8 @@ pokeplatinum_c = files( 'overlay025/ov25_02255540.c', 'overlay025/poketch_button.c', 'overlay025/ov25_02255DBC.c', - 'overlay026/ov26_022561C0.c', - 'overlay026/ov26_02256404.c', + 'poketch_digital_watch/main.c', + 'poketch_digital_watch/display.c', 'overlay027/ov27_022561C0.c', 'overlay027/ov27_0225680C.c', 'overlay028/ov28_022561C0.c', diff --git a/src/overlay025/poketch_system.c b/src/overlay025/poketch_system.c index 149684c67c..452f03d422 100644 --- a/src/overlay025/poketch_system.c +++ b/src/overlay025/poketch_system.c @@ -27,7 +27,7 @@ #include "unk_0201E3D8.h" #include "unk_02099D44.h" -FS_EXTERN_OVERLAY(overlay26); +FS_EXTERN_OVERLAY(poketch_digital_watch); FS_EXTERN_OVERLAY(overlay27); FS_EXTERN_OVERLAY(overlay28); FS_EXTERN_OVERLAY(overlay29); @@ -85,7 +85,7 @@ static const struct { int appID; FSOverlayID overlayID; } sAppOverlayIDs[] = { - { POKETCH_APPID_DIGITALWATCH, FS_OVERLAY_ID(overlay26) }, + { POKETCH_APPID_DIGITALWATCH, FS_OVERLAY_ID(poketch_digital_watch) }, { POKETCH_APPID_UNUSED_STOPWATCH, FS_OVERLAY_ID(overlay27) }, { POKETCH_APPID_CALCULATOR, FS_OVERLAY_ID(overlay28) }, { POKETCH_APPID_MEMOPAD, FS_OVERLAY_ID(overlay29) }, diff --git a/src/overlay026/ov26_022561C0.c b/src/overlay026/ov26_022561C0.c deleted file mode 100644 index 0493571699..0000000000 --- a/src/overlay026/ov26_022561C0.c +++ /dev/null @@ -1,232 +0,0 @@ -#include -#include -#include - -#include "overlay025/poketch_button.h" -#include "overlay025/poketch_system.h" -#include "overlay026/ov26_02256404.h" -#include "overlay026/struct_ov26_02256404_1.h" -#include "overlay026/struct_ov26_02256404_decl.h" - -#include "bg_window.h" -#include "heap.h" -#include "rtc.h" -#include "sys_task.h" -#include "sys_task_manager.h" -#include "touch_screen.h" - -typedef struct { - u8 unk_00; - u8 unk_01; - u8 unk_02; - u8 unk_03; - u8 unk_04; - u8 unk_05; - u8 unk_06; - u8 unk_07; - u32 unk_08; - u32 unk_0C; - PoketchButtonManager *buttonManager; - UnkStruct_ov26_02256404_1 unk_14; - UnkStruct_ov26_02256404 *unk_24; - PoketchSystem *poketchSys; -} UnkStruct_ov26_0225621C; - -static void NitroStaticInit(void); - -static BOOL ov26_022561D4(void **param0, PoketchSystem *poketchSys, BgConfig *param2, u32 param3); -static BOOL ov26_0225621C(UnkStruct_ov26_0225621C *param0, PoketchSystem *poketchSys, BgConfig *param2, u32 param3); -static void ov26_022562A4(UnkStruct_ov26_0225621C *param0); -static void ov26_022562BC(SysTask *param0, void *param1); -static void ov26_022562F8(void *param0); -static void ov26_02256300(u32 param0, u32 param1, u32 param2, void *param3); -static void ov26_0225631C(UnkStruct_ov26_0225621C *param0, u32 param1); -static BOOL ov26_02256330(UnkStruct_ov26_0225621C *param0); -static BOOL ov26_02256370(UnkStruct_ov26_0225621C *param0); -static BOOL ov26_022563D0(UnkStruct_ov26_0225621C *param0); - -static const TouchScreenHitTable Unk_ov26_02256718[] = { - { 0x10, 0xAF, 0x10, 0xCF } -}; - -static void NitroStaticInit(void) -{ - PoketchSystem_SetAppFunctions(ov26_022561D4, ov26_022562F8); -} - -static BOOL ov26_022561D4(void **param0, PoketchSystem *poketchSys, BgConfig *param2, u32 param3) -{ - UnkStruct_ov26_0225621C *v0 = (UnkStruct_ov26_0225621C *)Heap_AllocFromHeap(HEAP_ID_POKETCH_APP, sizeof(UnkStruct_ov26_0225621C)); - - if (v0 != NULL) { - if (ov26_0225621C(v0, poketchSys, param2, param3)) { - if (SysTask_Start(ov26_022562BC, v0, 1) != NULL) { - *param0 = v0; - return 1; - } - } - - Heap_FreeToHeap(v0); - } - - return 0; -} - -static BOOL ov26_0225621C(UnkStruct_ov26_0225621C *param0, PoketchSystem *poketchSys, BgConfig *param2, u32 param3) -{ - if (ov26_02256404(&(param0->unk_24), &(param0->unk_14), param2)) { - param0->unk_00 = 0; - param0->unk_01 = 0; - param0->unk_02 = 0; - param0->unk_03 = 1; - param0->unk_07 = 0; - param0->unk_14.unk_0C = 0; - - GetCurrentTime(&(param0->unk_14.unk_00)); - - if (param0->unk_14.unk_00.hour >= 24) { - param0->unk_14.unk_00.hour %= 24; - } - - if (param0->unk_14.unk_00.minute >= 60) { - param0->unk_14.unk_00.hour %= 60; - param0->unk_14.unk_00.minute %= 60; - } - - param0->unk_06 = param0->unk_14.unk_00.minute; - param0->unk_05 = param0->unk_14.unk_00.hour; - param0->buttonManager = PoketchButtonManager_New(Unk_ov26_02256718, NELEMS(Unk_ov26_02256718), ov26_02256300, param0, 8); - - if (param0->buttonManager == NULL) { - return 0; - } - - param0->poketchSys = poketchSys; - return 1; - } - - return 0; -} - -static void ov26_022562A4(UnkStruct_ov26_0225621C *param0) -{ - ov26_0225649C(param0->unk_24); - PoketchButtonManager_Free(param0->buttonManager); - Heap_FreeToHeap(param0); -} - -static void ov26_022562BC(SysTask *param0, void *param1) -{ - static BOOL (*const v0[])(UnkStruct_ov26_0225621C *) = { - ov26_02256330, - ov26_02256370, - ov26_022563D0, - }; - - UnkStruct_ov26_0225621C *v1 = (UnkStruct_ov26_0225621C *)param1; - - if (v1->unk_00 < NELEMS(v0)) { - PoketechSystem_UpdateButtonManager(v1->poketchSys, v1->buttonManager); - - if (v0[v1->unk_00](v1)) { - ov26_022562A4(v1); - SysTask_Done(param0); - PoketchSystem_NotifyAppUnloaded(v1->poketchSys); - } - } else { - } -} - -static void ov26_022562F8(void *param0) -{ - ((UnkStruct_ov26_0225621C *)param0)->unk_02 = 1; -} - -static void ov26_02256300(u32 param0, u32 param1, u32 param2, void *param3) -{ - UnkStruct_ov26_0225621C *v0 = (UnkStruct_ov26_0225621C *)param3; - - switch (param2) { - case 1: - v0->unk_14.unk_0C = 1; - v0->unk_07 = 1; - break; - case 0: - v0->unk_14.unk_0C = 0; - v0->unk_07 = 1; - break; - } -} - -static void ov26_0225631C(UnkStruct_ov26_0225621C *param0, u32 param1) -{ - if (param0->unk_02 == 0) { - param0->unk_00 = param1; - } else { - param0->unk_00 = 2; - } - - param0->unk_01 = 0; -} - -static BOOL ov26_02256330(UnkStruct_ov26_0225621C *param0) -{ - switch (param0->unk_01) { - case 0: - ov26_022564A8(param0->unk_24, 0); - param0->unk_01++; - break; - case 1: - if (ov26_022564CC(param0->unk_24, 0)) { - PoketchSystem_NotifyAppLoaded(param0->poketchSys); - ov26_0225631C(param0, 1); - } - break; - } - - return 0; -} - -static BOOL ov26_02256370(UnkStruct_ov26_0225621C *param0) -{ - if (param0->unk_02) { - ov26_0225631C(param0, 2); - return 0; - } - - if (param0->unk_07) { - param0->unk_07 = 0; - ov26_022564A8(param0->unk_24, 2); - } - - if (ov26_022564CC(param0->unk_24, 1)) { - param0->unk_06 = param0->unk_14.unk_00.minute; - param0->unk_05 = param0->unk_14.unk_00.hour; - GetCurrentTime(&(param0->unk_14.unk_00)); - - if ((param0->unk_06 != param0->unk_14.unk_00.minute) || (param0->unk_05 != param0->unk_14.unk_00.hour)) { - ov26_022564A8(param0->unk_24, 1); - } - } - - return 0; -} - -static BOOL ov26_022563D0(UnkStruct_ov26_0225621C *param0) -{ - switch (param0->unk_01) { - case 0: - ov26_022564A8(param0->unk_24, 3); - param0->unk_01++; - break; - - case 1: - if (ov26_022564D8(param0->unk_24)) { - return 1; - } - - break; - } - - return 0; -} diff --git a/src/overlay026/ov26_02256404.c b/src/overlay026/ov26_02256404.c deleted file mode 100644 index 9083195eac..0000000000 --- a/src/overlay026/ov26_02256404.c +++ /dev/null @@ -1,199 +0,0 @@ -#include "overlay026/ov26_02256404.h" - -#include -#include - -#include "overlay025/ov25_02254560.h" -#include "overlay025/ov25_02255090.h" -#include "overlay026/struct_ov26_02256404_1.h" -#include "overlay026/struct_ov26_02256404_decl.h" - -#include "bg_window.h" -#include "graphics.h" -#include "heap.h" -#include "sys_task_manager.h" - -struct UnkStruct_ov26_02256404_t { - const UnkStruct_ov26_02256404_1 *unk_00; - BgConfig *unk_04; - u32 unk_08[10]; - u16 unk_30[360]; -}; - -static void ov26_0225646C(const u16 *param0, u16 *param1); -static void ov26_022564E4(PoketchTaskManager *param0); -static void ov26_022564F8(SysTask *param0, void *param1); -static void ov26_0225658C(SysTask *param0, void *param1); -static void ov26_022565AC(SysTask *param0, void *param1); -static void ov26_022565D8(SysTask *param0, void *param1); -static void ov26_022565F4(UnkStruct_ov26_02256404 *param0); - -BOOL ov26_02256404(UnkStruct_ov26_02256404 **param0, const UnkStruct_ov26_02256404_1 *param1, BgConfig *param2) -{ - UnkStruct_ov26_02256404 *v0 = (UnkStruct_ov26_02256404 *)Heap_AllocFromHeap(HEAP_ID_POKETCH_APP, sizeof(UnkStruct_ov26_02256404)); - - if (v0 != NULL) { - NNSG2dScreenData *v1; - void *v2; - - PoketchTask_InitActiveTaskList(v0->unk_08, 8); - - v0->unk_00 = param1; - v0->unk_04 = Poketch_GetBgConfig(); - - v2 = Graphics_GetScrnData(12, 25, 1, &v1, 8); - - if (v2 == NULL) { - Heap_FreeToHeap(v0); - return 0; - } - - ov26_0225646C((const u16 *)(v1->rawData), v0->unk_30); - Heap_FreeToHeap(v2); - - *param0 = v0; - return 1; - } - - return 0; -} - -static void ov26_0225646C(const u16 *param0, u16 *param1) -{ - int v0, v1; - - v1 = 288; - - for (v0 = 0; v0 < 9; v0++) { - MI_CpuCopy16(param0, param1, 32 * 2); - MI_CpuCopy16(¶m0[v1], ¶m1[32], 8 * 2); - - param0 += 32; - param1 += (4 * 10); - - v1 = (v1 - 32 + 8); - } -} - -void ov26_0225649C(UnkStruct_ov26_02256404 *param0) -{ - if (param0 != NULL) { - Heap_FreeToHeap(param0); - } -} - -static const PoketchTask Unk_ov26_02256744[] = { - { 0x0, ov26_022564F8, 0x0 }, - { 0x1, ov26_0225658C, 0x0 }, - { 0x2, ov26_022565AC, 0x0 }, - { 0x3, ov26_022565D8, 0x0 }, - { 0x0, NULL, 0x0 } -}; - -void ov26_022564A8(UnkStruct_ov26_02256404 *param0, u32 param1) -{ - PoketchTask_Start(Unk_ov26_02256744, param1, param0, param0->unk_00, param0->unk_08, 2, 8); -} - -BOOL ov26_022564CC(UnkStruct_ov26_02256404 *param0, u32 param1) -{ - return PoketchTask_TaskIsNotActive(param0->unk_08, param1); -} - -BOOL ov26_022564D8(UnkStruct_ov26_02256404 *param0) -{ - return PoketchTask_NoActiveTasks(param0->unk_08); -} - -static void ov26_022564E4(PoketchTaskManager *param0) -{ - UnkStruct_ov26_02256404 *v0 = PoketchTask_GetTaskData(param0); - PoketchTask_EndTask(v0->unk_08, param0); -} - -static void ov26_022564F8(SysTask *param0, void *param1) -{ - static const BgTemplate v0 = { - 0, - 0, - 0x800, - 0, - 1, - GX_BG_COLORMODE_16, - GX_BG_SCRBASE_0x7000, - GX_BG_CHARBASE_0x00000, - GX_BG_EXTPLTT_01, - 2, - 0, - 0, - 0 - }; - GXSDispCnt v1; - UnkStruct_ov26_02256404 *v2; - - v2 = PoketchTask_GetTaskData(param1); - - Bg_InitFromTemplate(v2->unk_04, 6, &v0, 0); - Graphics_LoadTilesToBgLayer(12, 23, v2->unk_04, 6, 0, 0, 1, 8); - Graphics_LoadTilemapToBgLayer(12, 24, v2->unk_04, 6, 0, 0, 1, 8); - - Poketch_LoadActivePalette(0, 0); - ov26_022565F4(v2); - - Bg_CopyTilemapBufferToVRAM(v2->unk_04, 6); - - v1 = GXS_GetDispCnt(); - GXS_SetVisiblePlane(v1.visiblePlane | GX_PLANEMASK_BG2); - ov26_022564E4(param1); -} - -static void ov26_0225658C(SysTask *param0, void *param1) -{ - UnkStruct_ov26_02256404 *v0 = PoketchTask_GetTaskData(param1); - - ov26_022565F4(v0); - Bg_CopyTilemapBufferToVRAM(v0->unk_04, 6); - ov26_022564E4(param1); -} - -static void ov26_022565AC(SysTask *param0, void *param1) -{ - UnkStruct_ov26_02256404 *v0 = PoketchTask_GetTaskData(param1); - - if (v0->unk_00->unk_0C) { - Poketch_LoadActiveBacklightPalette(0, 0); - } else { - Poketch_LoadActivePalette(0, 0); - } - - ov26_022564E4(param1); -} - -static void ov26_022565D8(SysTask *param0, void *param1) -{ - UnkStruct_ov26_02256404 *v0 = PoketchTask_GetTaskData(param1); - - Bg_FreeTilemapBuffer(v0->unk_04, 6); - ov26_022564E4(param1); -} - -static void ov26_022565F4(UnkStruct_ov26_02256404 *param0) -{ - u32 v0, v1; - - CP_SetDiv32_32(param0->unk_00->unk_00.hour, 10); - - v0 = CP_GetDivResult32(); - v1 = CP_GetDivRemainder32(); - - Bg_CopyToTilemapRect(param0->unk_04, 6, 3, 7, 4, 9, param0->unk_30, 4 * v0, 0, (4 * 10), 9); - Bg_CopyToTilemapRect(param0->unk_04, 6, (3 + (4 + 1)), 7, 4, 9, param0->unk_30, 4 * v1, 0, (4 * 10), 9); - - CP_SetDiv32_32(param0->unk_00->unk_00.minute, 10); - - v0 = CP_GetDivResult32(); - v1 = CP_GetDivRemainder32(); - - Bg_CopyToTilemapRect(param0->unk_04, 6, 15, 7, 4, 9, param0->unk_30, 4 * v0, 0, (4 * 10), 9); - Bg_CopyToTilemapRect(param0->unk_04, 6, (15 + (4 + 1)), 7, 4, 9, param0->unk_30, 4 * v1, 0, (4 * 10), 9); -} diff --git a/src/poketch_digital_watch/display.c b/src/poketch_digital_watch/display.c new file mode 100644 index 0000000000..8d0b67d63c --- /dev/null +++ b/src/poketch_digital_watch/display.c @@ -0,0 +1,222 @@ +#include "poketch_digital_watch/display.h" + +#include +#include + +#include "overlay025/ov25_02254560.h" +#include "overlay025/ov25_02255090.h" + +#include "bg_window.h" +#include "graphics.h" +#include "heap.h" +#include "sys_task_manager.h" + +static void CopyDigitTilemap(const u16 *rawScreenData, u16 *dst); +static void EndTask(PoketchTaskManager *taskManager); +static void SetupBackground(SysTask *sysTask, void *taskManager); +static void UpdateClockDigits(SysTask *sysTask, void *taskManager); +static void ToggleBacklightPalette(SysTask *sysTask, void *taskManager); +static void FreeBackground(SysTask *sysTask, void *taskManager); +static void DrawClockDigits(DisplayManager *displayManager); + +BOOL PoketchDigitalWatch_SetupDisplayManager(DisplayManager **displayManager, const WatchData *watchData, BgConfig *bgConfig) +{ + DisplayManager *newDisplayManager = Heap_AllocFromHeap(HEAP_ID_POKETCH_APP, sizeof(DisplayManager)); + + if (newDisplayManager != NULL) { + NNSG2dScreenData *screenData; + + PoketchTask_InitActiveTaskList(newDisplayManager->taskList, NUM_TASK_SLOTS); + + newDisplayManager->watchData = watchData; + newDisplayManager->bgConfig = Poketch_GetBgConfig(); + + void *nscrBuffer = Graphics_GetScrnData(NARC_INDEX_GRAPHIC__POKETCH, POKETCH_CLOCK_DIGITS_TILEMAP_IDX, TRUE, &screenData, HEAP_ID_POKETCH_APP); + + if (nscrBuffer == NULL) { + Heap_FreeToHeap(newDisplayManager); + return FALSE; + } + + CopyDigitTilemap((const u16 *)(screenData->rawData), newDisplayManager->digitsTilemap); + Heap_FreeToHeap(nscrBuffer); + + *displayManager = newDisplayManager; + return TRUE; + } + + return FALSE; +} + +static void CopyDigitTilemap(const u16 *rawScreenData, u16 *dst) +{ + int offset = 9 * 32; + int row; + + for (row = 0; row < 9; row++) { + MI_CpuCopy16(rawScreenData, dst, 32 * sizeof(u16)); + MI_CpuCopy16(&rawScreenData[offset], &dst[32], 8 * sizeof(u16)); + + rawScreenData += 32; + dst += 40; + offset -= 24; + } +} + +void PoketchDigitalWatch_FreeDisplayManager(DisplayManager *displayManager) +{ + if (displayManager != NULL) { + Heap_FreeToHeap(displayManager); + } +} + +static const PoketchTask sDisplayTasks[] = { + { DISPLAY_TASK_SETUP_BACKGROUND, SetupBackground, 0 }, + { DISPLAY_TASK_UPDATE_WATCH_DIGITS, UpdateClockDigits, 0 }, + { DISPLAY_TASK_TOGGLE_BACKLIGHT, ToggleBacklightPalette, 0 }, + { DISPLAY_TASK_FREE_BACKGROUND, FreeBackground, 0 }, + { 0, NULL, 0 } +}; + +void PoketchDigitalWatch_StartDisplayTask(DisplayManager *displayManager, u32 taskID) +{ + PoketchTask_Start(sDisplayTasks, taskID, displayManager, displayManager->watchData, displayManager->taskList, 2, HEAP_ID_POKETCH_APP); +} + +BOOL PoketchDigitalWatch_DisplayTaskIsNotActive(DisplayManager *displayManager, u32 taskID) +{ + return PoketchTask_TaskIsNotActive(displayManager->taskList, taskID); +} + +BOOL PoketchDigitalWatch_NoActiveDisplayTasks(DisplayManager *displayManager) +{ + return PoketchTask_NoActiveTasks(displayManager->taskList); +} + +static void EndTask(PoketchTaskManager *taskManager) +{ + DisplayManager *displayManager = PoketchTask_GetTaskData(taskManager); + PoketchTask_EndTask(displayManager->taskList, taskManager); +} + +static void SetupBackground(SysTask *sysTask, void *taskManager) +{ + static const BgTemplate template = { + .x = 0, + .y = 0, + .bufferSize = 0x800, + .baseTile = 0, + .screenSize = BG_SCREEN_SIZE_256x256, + .colorMode = GX_BG_COLORMODE_16, + .screenBase = GX_BG_SCRBASE_0x7000, + .charBase = GX_BG_CHARBASE_0x00000, + .bgExtPltt = GX_BG_EXTPLTT_01, + .priority = 2, + .areaOver = 0, + .mosaic = FALSE, + }; + + DisplayManager *displayManager = PoketchTask_GetTaskData(taskManager); + + Bg_InitFromTemplate(displayManager->bgConfig, BG_LAYER_SUB_2, &template, BG_TYPE_STATIC); + Graphics_LoadTilesToBgLayer(NARC_INDEX_GRAPHIC__POKETCH, POKETCH_DIGITAL_WATCH_NARC_TILES_IDX, displayManager->bgConfig, BG_LAYER_SUB_2, 0, 0, TRUE, HEAP_ID_POKETCH_APP); + Graphics_LoadTilemapToBgLayer(NARC_INDEX_GRAPHIC__POKETCH, POKETCH_DIGITAL_WATCH_NARC_TILEMAP_IDX, displayManager->bgConfig, BG_LAYER_SUB_2, 0, 0, TRUE, HEAP_ID_POKETCH_APP); + + Poketch_LoadActivePalette(0, 0); + DrawClockDigits(displayManager); + + Bg_CopyTilemapBufferToVRAM(displayManager->bgConfig, BG_LAYER_SUB_2); + + GXSDispCnt displayControler = GXS_GetDispCnt(); + GXS_SetVisiblePlane(displayControler.visiblePlane | GX_PLANEMASK_BG2); + EndTask(taskManager); +} + +static void UpdateClockDigits(SysTask *sysTask, void *taskManager) +{ + DisplayManager *displayManager = PoketchTask_GetTaskData(taskManager); + + DrawClockDigits(displayManager); + Bg_CopyTilemapBufferToVRAM(displayManager->bgConfig, BG_LAYER_SUB_2); + EndTask(taskManager); +} + +static void ToggleBacklightPalette(SysTask *sysTask, void *taskManager) +{ + DisplayManager *displayManager = PoketchTask_GetTaskData(taskManager); + + if (displayManager->watchData->backlightActive) { + Poketch_LoadActiveBacklightPalette(0, 0); + } else { + Poketch_LoadActivePalette(0, 0); + } + + EndTask(taskManager); +} + +static void FreeBackground(SysTask *sysTask, void *taskManager) +{ + DisplayManager *displayManager = PoketchTask_GetTaskData(taskManager); + + Bg_FreeTilemapBuffer(displayManager->bgConfig, BG_LAYER_SUB_2); + EndTask(taskManager); +} + +static void DrawClockDigits(DisplayManager *displayManager) +{ + CP_SetDiv32_32(displayManager->watchData->time.hour, POKETCH_NUM_CLOCK_DIGITS); + + u32 tensDigitOffset = CP_GetDivResult32(); + u32 onesDigitOffset = CP_GetDivRemainder32(); + + Bg_CopyToTilemapRect(displayManager->bgConfig, + BG_LAYER_SUB_2, + POKETCH_CLOCK_HOURS_DIGIT_X, + POKETCH_CLOCK_HOURS_DIGIT_Y, + POKETCH_CLOCK_DIGIT_WIDTH, + POKETCH_CLOCK_DIGIT_HEIGHT, + displayManager->digitsTilemap, + POKETCH_CLOCK_DIGIT_WIDTH * tensDigitOffset, + 0, + POKETCH_CLOCK_DIGIT_WIDTH * POKETCH_NUM_CLOCK_DIGITS, + POKETCH_CLOCK_DIGIT_HEIGHT); + Bg_CopyToTilemapRect(displayManager->bgConfig, + BG_LAYER_SUB_2, + POKETCH_CLOCK_HOURS_DIGIT_X + POKETCH_CLOCK_DIGIT_WIDTH + POKETCH_CLOCK_DIGIT_GAP, + POKETCH_CLOCK_HOURS_DIGIT_Y, + POKETCH_CLOCK_DIGIT_WIDTH, + POKETCH_CLOCK_DIGIT_HEIGHT, + displayManager->digitsTilemap, + POKETCH_CLOCK_DIGIT_WIDTH * onesDigitOffset, + 0, + POKETCH_CLOCK_DIGIT_WIDTH * POKETCH_NUM_CLOCK_DIGITS, + POKETCH_CLOCK_DIGIT_HEIGHT); + + CP_SetDiv32_32(displayManager->watchData->time.minute, POKETCH_NUM_CLOCK_DIGITS); + + tensDigitOffset = CP_GetDivResult32(); + onesDigitOffset = CP_GetDivRemainder32(); + + Bg_CopyToTilemapRect(displayManager->bgConfig, + BG_LAYER_SUB_2, + POKETCH_CLOCK_MINUTES_DIGIT_X, + POKETCH_CLOCK_MINUTES_DIGIT_Y, + POKETCH_CLOCK_DIGIT_WIDTH, + POKETCH_CLOCK_DIGIT_HEIGHT, + displayManager->digitsTilemap, + POKETCH_CLOCK_DIGIT_WIDTH * tensDigitOffset, + 0, + POKETCH_CLOCK_DIGIT_WIDTH * POKETCH_NUM_CLOCK_DIGITS, + POKETCH_CLOCK_DIGIT_HEIGHT); + Bg_CopyToTilemapRect(displayManager->bgConfig, + BG_LAYER_SUB_2, + POKETCH_CLOCK_MINUTES_DIGIT_X + POKETCH_CLOCK_DIGIT_WIDTH + POKETCH_CLOCK_DIGIT_GAP, + POKETCH_CLOCK_MINUTES_DIGIT_Y, + POKETCH_CLOCK_DIGIT_WIDTH, + POKETCH_CLOCK_DIGIT_HEIGHT, + displayManager->digitsTilemap, + POKETCH_CLOCK_DIGIT_WIDTH * onesDigitOffset, + 0, + POKETCH_CLOCK_DIGIT_WIDTH * POKETCH_NUM_CLOCK_DIGITS, + POKETCH_CLOCK_DIGIT_HEIGHT); +} diff --git a/src/poketch_digital_watch/main.c b/src/poketch_digital_watch/main.c new file mode 100644 index 0000000000..56f449429b --- /dev/null +++ b/src/poketch_digital_watch/main.c @@ -0,0 +1,238 @@ +#include +#include +#include + +#include "overlay025/poketch_button.h" +#include "overlay025/poketch_system.h" +#include "poketch_digital_watch/display.h" + +#include "bg_window.h" +#include "heap.h" +#include "rtc.h" +#include "sys_task.h" +#include "sys_task_manager.h" +#include "touch_screen.h" + +// App Tasks +#define APP_TASK_LOAD 0 +#define APP_TASK_UPDATE 1 +#define APP_TASK_UNLOAD 2 + +// Touch Screen Boundaries +#define BACKLIGHT_BUTTON_MIN_Y 0x10 +#define BACKLIGHT_BUTTON_MAX_Y 0xAF +#define BACKLIGHT_BUTTON_MIN_X 0x10 +#define BACKLIGHT_BUTTON_MAX_X 0xCF + +typedef struct { + u8 activeTask; + u8 state; + u8 shutdown; + u8 unused_0; // Assigned value of 1 + u8 unused_1; + u8 hour; + u8 minute; + u8 backlightChange; + u8 unused_2[8]; + PoketchButtonManager *buttonManager; + WatchData watchData; + DisplayManager *displayManager; + PoketchSystem *poketchSys; +} AppData; + +static void NitroStaticInit(void); + +static BOOL Init(void **appData, PoketchSystem *poketchSys, BgConfig *bgConfig, u32 appID); +static BOOL SetupAppData(AppData *appData, PoketchSystem *poketchSys, BgConfig *bgConfig, u32 appID); +static void FreeAppData(AppData *appData); +static void Main(SysTask *sysTask, void *taskManager); +static void Exit(void *appData); +static void ToggleBacklight(u32 btnNumber, u32 buttonState, u32 touchState, void *appDataIn); +static void ChangeActiveTask(AppData *appData, u32 taskID); +static BOOL LoadApp(AppData *appData); +static BOOL UpdateApp(AppData *appData); +static BOOL UnloadApp(AppData *appData); + +static const TouchScreenHitTable sButtonHitTable[] = { + { BACKLIGHT_BUTTON_MIN_Y, BACKLIGHT_BUTTON_MAX_Y, BACKLIGHT_BUTTON_MIN_X, BACKLIGHT_BUTTON_MAX_X } +}; + +static void NitroStaticInit(void) +{ + PoketchSystem_SetAppFunctions(Init, Exit); +} + +static BOOL Init(void **appData, PoketchSystem *poketchSys, BgConfig *bgConfig, u32 appID) +{ + AppData *newAppData = Heap_AllocFromHeap(HEAP_ID_POKETCH_APP, sizeof(AppData)); + + if (newAppData != NULL) { + if (SetupAppData(newAppData, poketchSys, bgConfig, appID) + && SysTask_Start(Main, newAppData, 1)) { + *appData = newAppData; + return TRUE; + } + + Heap_FreeToHeap(newAppData); + } + + return FALSE; +} + +static BOOL SetupAppData(AppData *appData, PoketchSystem *poketchSys, BgConfig *bgConfig, u32 appID) +{ + if (PoketchDigitalWatch_SetupDisplayManager(&(appData->displayManager), &(appData->watchData), bgConfig)) { + appData->activeTask = APP_TASK_LOAD; + appData->state = 0; + appData->shutdown = FALSE; + appData->unused_0 = 1; + appData->backlightChange = FALSE; + appData->watchData.backlightActive = FALSE; + + GetCurrentTime(&(appData->watchData.time)); + + if (appData->watchData.time.hour >= 24) { + appData->watchData.time.hour %= 24; + } + + if (appData->watchData.time.minute >= 60) { + appData->watchData.time.hour %= 60; + appData->watchData.time.minute %= 60; + } + + appData->minute = appData->watchData.time.minute; + appData->hour = appData->watchData.time.hour; + appData->buttonManager = PoketchButtonManager_New(sButtonHitTable, NELEMS(sButtonHitTable), ToggleBacklight, appData, HEAP_ID_POKETCH_APP); + + if (appData->buttonManager == NULL) { + return FALSE; + } + + appData->poketchSys = poketchSys; + return TRUE; + } + + return FALSE; +} + +static void FreeAppData(AppData *appData) +{ + PoketchDigitalWatch_FreeDisplayManager(appData->displayManager); + PoketchButtonManager_Free(appData->buttonManager); + Heap_FreeToHeap(appData); +} + +static void Main(SysTask *sysTask, void *callbackData) +{ + static BOOL (*const funcArray[])(AppData *) = { + LoadApp, + UpdateApp, + UnloadApp, + }; + + AppData *appData = callbackData; + + if (appData->activeTask < NELEMS(funcArray)) { + PoketechSystem_UpdateButtonManager(appData->poketchSys, appData->buttonManager); + + if (funcArray[appData->activeTask](appData)) { + FreeAppData(appData); + SysTask_Done(sysTask); + PoketchSystem_NotifyAppUnloaded(appData->poketchSys); + } + } +} + +static void Exit(void *appData) +{ + ((AppData *)appData)->shutdown = TRUE; +} + +static void ToggleBacklight(u32 btnNumber, u32 buttonState, u32 touchState, void *appDataIn) +{ + AppData *appData = appDataIn; + + switch (touchState) { + case TRUE: + appData->watchData.backlightActive = TRUE; + appData->backlightChange = TRUE; + break; + case FALSE: + appData->watchData.backlightActive = FALSE; + appData->backlightChange = TRUE; + break; + } +} + +static void ChangeActiveTask(AppData *appData, u32 taskID) +{ + if (appData->shutdown == FALSE) { + appData->activeTask = taskID; + } else { + appData->activeTask = APP_TASK_UNLOAD; + } + + appData->state = 0; +} + +static BOOL LoadApp(AppData *appData) +{ + switch (appData->state) { + case 0: + PoketchDigitalWatch_StartDisplayTask(appData->displayManager, DISPLAY_TASK_SETUP_BACKGROUND); + appData->state++; + break; + case 1: + if (PoketchDigitalWatch_DisplayTaskIsNotActive(appData->displayManager, DISPLAY_TASK_SETUP_BACKGROUND)) { + PoketchSystem_NotifyAppLoaded(appData->poketchSys); + ChangeActiveTask(appData, APP_TASK_UPDATE); + } + break; + } + + return FALSE; +} + +static BOOL UpdateApp(AppData *appData) +{ + if (appData->shutdown) { + ChangeActiveTask(appData, APP_TASK_UNLOAD); + return FALSE; + } + + if (appData->backlightChange) { + appData->backlightChange = FALSE; + PoketchDigitalWatch_StartDisplayTask(appData->displayManager, DISPLAY_TASK_TOGGLE_BACKLIGHT); + } + + if (PoketchDigitalWatch_DisplayTaskIsNotActive(appData->displayManager, DISPLAY_TASK_UPDATE_WATCH_DIGITS)) { + appData->minute = appData->watchData.time.minute; + appData->hour = appData->watchData.time.hour; + GetCurrentTime(&(appData->watchData.time)); + + if ((appData->minute != appData->watchData.time.minute) || (appData->hour != appData->watchData.time.hour)) { + PoketchDigitalWatch_StartDisplayTask(appData->displayManager, DISPLAY_TASK_UPDATE_WATCH_DIGITS); + } + } + + return FALSE; +} + +static BOOL UnloadApp(AppData *appData) +{ + switch (appData->state) { + case 0: + PoketchDigitalWatch_StartDisplayTask(appData->displayManager, DISPLAY_TASK_FREE_BACKGROUND); + appData->state++; + break; + + case 1: + if (PoketchDigitalWatch_NoActiveDisplayTasks(appData->displayManager)) { + return TRUE; + } + + break; + } + + return FALSE; +}