Merge pull request #388 from lucie-sharpe/PoketchDigitalClockApp
Some checks failed
build / build (push) Has been cancelled

Poketch digital clock app
This commit is contained in:
Rachel
2025-02-20 10:31:45 -08:00
committed by GitHub
12 changed files with 518 additions and 471 deletions

View File

@@ -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

View File

@@ -1,11 +0,0 @@
#ifndef POKEPLATINUM_STRUCT_OV26_02256404_1_H
#define POKEPLATINUM_STRUCT_OV26_02256404_1_H
#include <nitro/rtc.h>
typedef struct {
RTCTime unk_00;
u32 unk_0C;
} UnkStruct_ov26_02256404_1;
#endif // POKEPLATINUM_STRUCT_OV26_02256404_1_H

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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',

View File

@@ -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) },

View File

@@ -1,232 +0,0 @@
#include <nitro.h>
#include <nitro/sinit.h>
#include <string.h>
#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;
}

View File

@@ -1,199 +0,0 @@
#include "overlay026/ov26_02256404.h"
#include <nitro.h>
#include <string.h>
#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(&param0[v1], &param1[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);
}

View File

@@ -0,0 +1,222 @@
#include "poketch_digital_watch/display.h"
#include <nitro.h>
#include <string.h>
#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);
}

View File

@@ -0,0 +1,238 @@
#include <nitro.h>
#include <nitro/sinit.h>
#include <string.h>
#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;
}