From baffd08f49b4399679b0f895e0463d61a3a4d04a Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 13:22:48 -0500 Subject: [PATCH 01/12] Rename rom header, payload symbol --- asm/loader.s | 4 ++-- asm/{berry_fix_header.inc => rom_header.inc} | 0 data/data.s | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename asm/{berry_fix_header.inc => rom_header.inc} (100%) diff --git a/asm/loader.s b/asm/loader.s index 194a107..a9d5fca 100644 --- a/asm/loader.s +++ b/asm/loader.s @@ -18,7 +18,7 @@ _start: @ 0 b _entry arm_func_end _start - .include "asm/berry_fix_header.inc" + .include "asm/rom_header.inc" @ C0 .word 0 @@ -107,7 +107,7 @@ _1a0: bne _1a0 mov r1, #0 strh r1, [r0, 0xa] @ SIOMLT_SEND - ldr r0, =_data_2f0 + ldr r0, =gPayload ldr r1, =gCode swi 0x11 << 16 ldr lr, =gCode diff --git a/asm/berry_fix_header.inc b/asm/rom_header.inc similarity index 100% rename from asm/berry_fix_header.inc rename to asm/rom_header.inc diff --git a/data/data.s b/data/data.s index dbb86b1..8159215 100644 --- a/data/data.s +++ b/data/data.s @@ -1,4 +1,4 @@ .section .rodata -_data_2f0:: +gPayload:: .incbin "data/payload.gba.lz" From e6848b339ae9e3b0ad1a7c00aba1fa7b8963e028 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 13:50:04 -0500 Subject: [PATCH 02/12] Pare down global header --- payload/include/constants/game_stat.h | 56 -- payload/include/global.berry.h | 62 -- payload/include/global.fieldmap.h | 310 ---------- payload/include/global.h | 838 +------------------------- payload/include/pokemon.h | 154 ----- 5 files changed, 23 insertions(+), 1397 deletions(-) delete mode 100644 payload/include/constants/game_stat.h delete mode 100644 payload/include/global.berry.h delete mode 100644 payload/include/global.fieldmap.h delete mode 100644 payload/include/pokemon.h diff --git a/payload/include/constants/game_stat.h b/payload/include/constants/game_stat.h deleted file mode 100644 index 47d703d..0000000 --- a/payload/include/constants/game_stat.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef GUARD_CONSTANTS_GAME_STAT_H -#define GUARD_CONSTANTS_GAME_STAT_H - -#define GAME_STAT_SAVED_GAME 0 -#define GAME_STAT_FIRST_HOF_PLAY_TIME 1 -#define GAME_STAT_STARTED_TRENDS 2 -#define GAME_STAT_PLANTED_BERRIES 3 -#define GAME_STAT_TRADED_BIKES 4 -#define GAME_STAT_STEPS 5 -#define GAME_STAT_GOT_INTERVIEWED 6 -#define GAME_STAT_TOTAL_BATTLES 7 -#define GAME_STAT_WILD_BATTLES 8 -#define GAME_STAT_TRAINER_BATTLES 9 -#define GAME_STAT_ENTERED_HOF 10 -#define GAME_STAT_POKEMON_CAPTURES 11 -#define GAME_STAT_FISHING_CAPTURES 12 -#define GAME_STAT_HATCHED_EGGS 13 -#define GAME_STAT_EVOLVED_POKEMON 14 -#define GAME_STAT_USED_POKECENTER 15 -#define GAME_STAT_RESTED_AT_HOME 16 -#define GAME_STAT_ENTERED_SAFARI_ZONE 17 -#define GAME_STAT_USED_CUT 18 -#define GAME_STAT_USED_ROCK_SMASH 19 -#define GAME_STAT_MOVED_SECRET_BASE 20 -#define GAME_STAT_POKEMON_TRADES 21 -#define GAME_STAT_UNKNOWN_22 22 -#define GAME_STAT_LINK_BATTLE_WINS 23 -#define GAME_STAT_LINK_BATTLE_LOSSES 24 -#define GAME_STAT_LINK_BATTLE_DRAWS 25 -#define GAME_STAT_USED_SPLASH 26 -#define GAME_STAT_USED_STRUGGLE 27 -#define GAME_STAT_SLOT_JACKPOTS 28 -#define GAME_STAT_CONSECUTIVE_ROULETTE_WINS 29 -#define GAME_STAT_ENTERED_BATTLE_TOWER 30 -#define GAME_STAT_UNKNOWN_31 31 -#define GAME_STAT_BATTLE_TOWER_BEST_STREAK 32 -#define GAME_STAT_POKEBLOCKS 33 -#define GAME_STAT_POKEBLOCKS_WITH_FRIENDS 34 -#define GAME_STAT_WON_LINK_CONTEST 35 -#define GAME_STAT_ENTERED_CONTEST 36 -#define GAME_STAT_WON_CONTEST 37 -#define GAME_STAT_SHOPPED 38 -#define GAME_STAT_USED_ITEMFINDER 39 -#define GAME_STAT_GOT_RAINED_ON 40 -#define GAME_STAT_CHECKED_POKEDEX 41 -#define GAME_STAT_RECEIVED_RIBBONS 42 -#define GAME_STAT_JUMPED_DOWN_LEDGES 43 -#define GAME_STAT_WATCHED_TV 44 -#define GAME_STAT_CHECKED_CLOCK 45 -#define GAME_STAT_WON_POKEMON_LOTTERY 46 -#define GAME_STAT_USED_DAYCARE 47 -#define GAME_STAT_RODE_CABLE_CAR 48 -#define GAME_STAT_ENTERED_HOT_SPRINGS 49 -#define NUM_GAME_STATS 50 - -#endif // GUARD_CONSTANTS_GAME_STAT_H diff --git a/payload/include/global.berry.h b/payload/include/global.berry.h deleted file mode 100644 index 8f185c8..0000000 --- a/payload/include/global.berry.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GUARD_GLOBAL_BERRY_H -#define GUARD_GLOBAL_BERRY_H - -struct Berry -{ - /*0x00*/ u8 name[7]; - /*0x07*/ u8 firmness; - /*0x08*/ u16 size; - /*0x0A*/ u8 maxYield; - /*0x0B*/ u8 minYield; - /*0x0C*/ const u8 *description1; - /*0x10*/ const u8 *description2; - /*0x14*/ u8 stageDuration; - /*0x15*/ u8 spicy; - /*0x16*/ u8 dry; - /*0x17*/ u8 sweet; - /*0x18*/ u8 bitter; - /*0x19*/ u8 sour; - /*0x1A*/ u8 smoothness; -}; - -struct EnigmaBerry -{ - /*0x000*/ struct Berry berry; - /*0x01B*/ u8 pic[(6 * 6) * TILE_SIZE_4BPP]; - /*0x49C*/ u16 palette[16]; - /*0x4BC*/ u8 description1[45]; - /*0x4E9*/ u8 description2[45]; - /*0x516*/ u8 itemEffect[18]; - /*0x528*/ u8 holdEffect; - /*0x529*/ u8 holdEffectParam; - /*0x52C*/ u32 checksum; -}; - -struct BattleEnigmaBerry -{ - /*0x00*/ u8 name[7]; - /*0x07*/ u8 holdEffect; - /*0x08*/ u8 itemEffect[18]; - /*0x1A*/ u8 holdEffectParam; -}; - -struct BerryTree -{ - /*0x00*/ u8 berry; - /*0x01*/ u8 stage:7; - /* - A berry sparkle is a state that a berry tree - can be in after growing within the player's - viewport. - */ - /*0x01*/ bool8 growthSparkle:1; - /*0x02*/ u16 minutesUntilNextStage; - /*0x04*/ u8 berryYield; - /*0x05*/ u8 regrowthCount:4; - /*0x05*/ u8 watered1:1; - /*0x05*/ u8 watered2:1; - /*0x05*/ u8 watered3:1; - /*0x05*/ u8 watered4:1; -}; - -#endif // GUARD_GLOBAL_BERRY_H diff --git a/payload/include/global.fieldmap.h b/payload/include/global.fieldmap.h deleted file mode 100644 index e7150b4..0000000 --- a/payload/include/global.fieldmap.h +++ /dev/null @@ -1,310 +0,0 @@ -#ifndef GUARD_GLOBAL_FIELDMAP_H -#define GUARD_GLOBAL_FIELDMAP_H - -enum -{ - CONNECTION_SOUTH = 1, - CONNECTION_NORTH, - CONNECTION_WEST, - CONNECTION_EAST, - CONNECTION_DIVE, - CONNECTION_EMERGE -}; - -typedef void (*TilesetCB)(void); - -struct Tileset -{ - /*0x00*/ bool8 isCompressed; - /*0x01*/ bool8 isSecondary; - /*0x04*/ void *tiles; - /*0x08*/ void *palettes; - /*0x0c*/ void *metatiles; - /*0x10*/ void *metatileAttributes; - /*0x14*/ TilesetCB callback; -}; - -struct MapLayout -{ - /*0x00*/ s32 width; - /*0x04*/ s32 height; - /*0x08*/ u16 *border; - /*0x0c*/ u16 *map; - /*0x10*/ struct Tileset *primaryTileset; - /*0x14*/ struct Tileset *secondaryTileset; -}; - -struct BackupMapLayout -{ - s32 width; - s32 height; - u16 *map; -}; - -struct EventObjectTemplate -{ - /*0x00*/ u8 localId; - /*0x01*/ u8 graphicsId; - /*0x02*/ u8 unk2; - /*0x04*/ s16 x; - /*0x06*/ s16 y; - /*0x08*/ u8 elevation; - /*0x09*/ u8 movementType; - /*0x0A*/ u8 movementRangeX:4; - u8 movementRangeY:4; - /*0x0C*/ u16 trainerType; - /*0x0E*/ u16 trainerRange_berryTreeId; - /*0x10*/ u8 *script; - /*0x14*/ u16 flagId; -}; - -struct WarpEvent -{ - s16 x, y; - u8 elevation; - u8 warpId; - u8 mapNum; - u8 mapGroup; -}; - -struct CoordEvent -{ - s16 x, y; - u8 elevation; - u16 trigger; - u16 index; - u8 filler_A[0x2]; - u8 *script; -}; - -struct BgEvent -{ - u16 x, y; - u8 elevation; - u8 kind; // The "kind" field determines how to access bgUnion union below. - union { - u8 *script; - struct { - u16 item; - u16 hiddenItemId; - } hiddenItem; - u32 secretBaseId; - } bgUnion; -}; - -struct MapEvents -{ - u8 eventObjectCount; - u8 warpCount; - u8 coordEventCount; - u8 bgEventCount; - - struct EventObjectTemplate *eventObjects; - struct WarpEvent *warps; - struct CoordEvent *coordEvents; - struct BgEvent *bgEvents; -}; - -struct MapConnection -{ - /*0x00*/ u8 direction; - /*0x01*/ u32 offset; - /*0x05*/ u8 mapGroup; - /*0x06*/ u8 mapNum; -}; - -struct MapConnections -{ - s32 count; - struct MapConnection *connections; -}; - -struct MapHeader -{ - /* 0x00 */ struct MapLayout *mapLayout; - /* 0x04 */ struct MapEvents *events; - /* 0x08 */ u8 *mapScripts; - /* 0x0C */ struct MapConnections *connections; - /* 0x10 */ u16 music; - /* 0x12 */ u16 mapLayoutId; - /* 0x14 */ u8 regionMapSectionId; - /* 0x15 */ u8 cave; - /* 0x16 */ u8 weather; - /* 0x17 */ u8 mapType; - /* 0x18 */ u8 filler_18; - /* 0x19 */ u8 escapeRope; - /* 0x1A */ u8 flags; - /* 0x1B */ u8 battleType; -}; - -struct EventObject -{ - /*0x00*/ u32 active:1; - u32 singleMovementActive:1; - u32 triggerGroundEffectsOnMove:1; - u32 triggerGroundEffectsOnStop:1; - u32 disableCoveringGroundEffects:1; // disables ground effects that cover parts of the object's sprite - u32 landingJump:1; - u32 heldMovementActive:1; - u32 heldMovementFinished:1; - /*0x01*/ u32 frozen:1; - u32 facingDirectionLocked:1; - u32 disableAnim:1; // used to disable forced movement sliding animations (like on ice) - u32 enableAnim:1; - u32 inanimate:1; - u32 invisible:1; - u32 offScreen:1; - u32 trackedByCamera:1; // only set for the player object - /*0x02*/ u32 isPlayer:1; - u32 hasReflection:1; - u32 inShortGrass:1; - u32 inShallowFlowingWater:1; - u32 inSandPile:1; - u32 inHotSprings:1; - u32 hasShadow:1; - u32 spriteAnimPausedBackup:1; - /*0x03*/ u32 spriteAffineAnimPausedBackup:1; - u32 disableJumpLandingGroundEffect:1; - u32 fixedPriority:1; - /*0x04*/ u8 spriteId; - /*0x05*/ u8 graphicsId; - /*0x06*/ u8 movementType; - /*0x07*/ u8 trainerType; - /*0x08*/ u8 localId; - /*0x09*/ u8 mapNum; - /*0x0A*/ u8 mapGroup; - /*0x0B*/ u8 currentElevation:4; - u8 previousElevation:4; - /*0x0C*/ struct Coords16 initialCoords; - /*0x10*/ struct Coords16 currentCoords; - /*0x14*/ struct Coords16 previousCoords; - /*0x18*/ u8 facingDirection:4; - /*0x18*/ u8 movementDirection:4; - /*0x19*/ union __attribute__((packed)) { - u8 as_byte; - struct __attribute__((packed)) { - u16 x:4; - u16 y:4; - } as_nybbles; - } range; - /*0x1A*/ u8 fieldEffectSpriteId; - /*0x1B*/ u8 warpArrowSpriteId; - /*0x1C*/ u8 movementActionId; - /*0x1D*/ u8 trainerRange_berryTreeId; - /*0x1E*/ u8 currentMetatileBehavior; - /*0x1F*/ u8 previousMetatileBehavior; - /*0x20*/ u8 previousMovementDirection; - /*0x21*/ u8 directionSequenceIndex; - /*0x22*/ u8 playerCopyableMovement; // used as an index to gCopyPlayerMovementFuncs for the "copy player" movement types - /*size = 0x24*/ -}; - -struct EventObjectGraphicsInfo -{ - /*0x00*/ u16 tileTag; - /*0x02*/ u16 paletteTag; - /*0x04*/ u16 bridgeReflectionPaletteTag; - /*0x06*/ u16 size; - /*0x08*/ s16 width; - /*0x0A*/ s16 height; - /*0x0C*/ u8 paletteSlot:4; - u8 shadowSize:2; - u8 inanimate:1; - u8 disableReflectionPaletteLoad:1; - /*0x0D*/ u8 tracks; - /*0x10*/ const struct OamData *oam; - /*0x14*/ const struct SubspriteTable *subspriteTables; - /*0x18*/ const union AnimCmd *const *anims; - /*0x1C*/ const struct SpriteFrameImage *images; - /*0x20*/ const union AffineAnimCmd *const *affineAnims; -}; - -#define PLAYER_AVATAR_FLAG_ON_FOOT (1 << 0) -#define PLAYER_AVATAR_FLAG_MACH_BIKE (1 << 1) -#define PLAYER_AVATAR_FLAG_ACRO_BIKE (1 << 2) -#define PLAYER_AVATAR_FLAG_SURFING (1 << 3) -#define PLAYER_AVATAR_FLAG_UNDERWATER (1 << 4) -#define PLAYER_AVATAR_FLAG_CONTROLLABLE (1 << 5) -#define PLAYER_AVATAR_FLAG_FORCED_MOVE (1 << 6) -#define PLAYER_AVATAR_FLAG_DASH (1 << 7) - -enum -{ - ACRO_BIKE_NORMAL, - ACRO_BIKE_TURNING, - ACRO_BIKE_WHEELIE_STANDING, - ACRO_BIKE_BUNNY_HOP, - ACRO_BIKE_WHEELIE_MOVING, - ACRO_BIKE_STATE5, - ACRO_BIKE_STATE6, -}; - -enum -{ - DIR_NONE, - DIR_SOUTH, - DIR_NORTH, - DIR_WEST, - DIR_EAST, - DIR_SOUTHWEST, - DIR_SOUTHEAST, - DIR_NORTHWEST, - DIR_NORTHEAST, -}; - -enum -{ - COLLISION_LEDGE_JUMP = 6 -}; - -// player running states -enum -{ - NOT_MOVING, - TURN_DIRECTION, // not the same as turning! turns your avatar without moving. also known as a turn frame in some circles - MOVING, -}; - -// player tile transition states -enum -{ - T_NOT_MOVING, - T_TILE_TRANSITION, - T_TILE_CENTER, // player is on a frame in which they are centered on a tile during which the player either stops or keeps their momentum and keeps going, changing direction if necessary. -}; - -struct PlayerAvatar /* 0x202E858 */ -{ - /*0x00*/ u8 flags; - /*0x01*/ u8 unk1; // used to be named bike, but its definitely not that. seems to be some transition flags - /*0x02*/ u8 runningState; // this is a static running state. 00 is not moving, 01 is turn direction, 02 is moving. - /*0x03*/ u8 tileTransitionState; // this is a transition running state: 00 is not moving, 01 is transition between tiles, 02 means you are on the frame in which you have centered on a tile but are about to keep moving, even if changing directions. 2 is also used for a ledge hop, since you are transitioning. - /*0x04*/ u8 spriteId; - /*0x05*/ u8 eventObjectId; - /*0x06*/ bool8 preventStep; - /*0x07*/ u8 gender; - /*0x08*/ u8 acroBikeState; // 00 is normal, 01 is turning, 02 is standing wheelie, 03 is hopping wheelie - /*0x09*/ u8 newDirBackup; // during bike movement, the new direction as opposed to player's direction is backed up here. - /*0x0A*/ u8 bikeFrameCounter; // on the mach bike, when this value is 1, the bike is moving but not accelerating yet for 1 tile. on the acro bike, this acts as a timer for acro bike. - /*0x0B*/ u8 bikeSpeed; - // acro bike only - /*0x0C*/ u32 directionHistory; // up/down/left/right history is stored in each nybble, but using the field directions and not the io inputs. - /*0x10*/ u32 abStartSelectHistory; // same as above but for A + B + start + select only - // these two are timer history arrays which [0] is the active timer for acro bike. every element is backed up to the next element upon update. - /*0x14*/ u8 dirTimerHistory[8]; - /*0x1C*/ u8 abStartSelectTimerHistory[8]; -}; - -struct Camera -{ - bool8 active:1; - s32 x; - s32 y; -}; - -extern struct EventObject gMapObjects[]; -extern u8 gSelectedEventObject; -extern struct MapHeader gMapHeader; -extern struct PlayerAvatar gPlayerAvatar; - -#endif // GUARD_GLOBAL_FIELDMAP_H diff --git a/payload/include/global.h b/payload/include/global.h index 4bea138..a6bcd6b 100644 --- a/payload/include/global.h +++ b/payload/include/global.h @@ -3,8 +3,6 @@ #include "gba/gba.h" -// global.h from pokemon ruby - // IDE support #if defined(__APPLE__) || defined(__CYGWIN__) || defined(__INTELLISENSE__) // We define these when using certain IDEs to fool preproc @@ -19,62 +17,25 @@ #define INCBIN_S32 INCBIN #endif // IDE support -// Prevent cross-jump optimization. -#define BLOCK_CROSS_JUMP asm(""); - -// to help in decompiling -#define asm_comment(x) asm volatile("@ -- " x " -- ") - -#define asm_unified(x) asm(".syntax unified\n" x "\n.syntax divided\n") - #define ARRAY_COUNT(array) (sizeof(array) / sizeof((array)[0])) +#define RomHeaderGameTitle ((const char *)0x080000A0) +#define RomHeaderGameCode ((const char *)0x080000AC) +#define RomHeaderMakerCode ((const char *)0x080000B0) +#define RomHeaderMagic ((const u8 *) 0x080000B2) +#define RomHeaderSoftwareVersion ((const u8 *) 0x080000BC) + +#define LocalTimeOffset ((struct Time *)0x02028098) +#define LastBerryTreeUpdate ((struct Time *)0x020280A0) #define POKEMON_SLOTS_NUMBER 412 #define POKEMON_NAME_LENGTH 10 #define OT_NAME_LENGTH 7 +#define VARS_COUNT 256 #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) >= (b) ? (a) : (b)) -// why does GF hate 2d arrays -#define MULTI_DIM_ARR(x, dim, y) ((x) * dim + (y)) - -// dim access enums -enum -{ - B_8 = 1, - B_16 = 2, - B_32 = 4 -}; - -// There are many quirks in the source code which have overarching behavioral differences from -// a number of other files. For example, diploma.c seems to declare rodata before each use while -// other files declare out of order and must be at the beginning. There are also a number of -// macros which differ from one file to the next due to the method of obtaining the result, such -// as these below. Because of this, there is a theory (Two Team Theory) that states that these -// programming projects had more than 1 "programming team" which utilized different macros for -// each of the files that were worked on. -#define T1_READ_8(ptr) ((ptr)[0]) -#define T1_READ_16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) -#define T1_READ_32(ptr) ((ptr)[0] | ((ptr)[1] << 8) | ((ptr)[2] << 16) | ((ptr)[3] << 24)) -#define T1_READ_PTR(ptr) (u8*) T1_READ_32(ptr) - -// T2_READ_8 is a duplicate to remain consistent with each group. -#define T2_READ_8(ptr) ((ptr)[0]) -#define T2_READ_16(ptr) ((ptr)[0] + ((ptr)[1] << 8)) -#define T2_READ_32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) -#define T2_READ_PTR(ptr) (void*) T2_READ_32(ptr) - -// Credits to Made (dolphin emoji) -#define S16TOPOSFLOAT(val) \ -({ \ - s16 v = (val); \ - float f = (float)v; \ - if(v < 0) f += 65536.0f; \ - f; \ -}) - enum { VERSION_SAPPHIRE = 1, @@ -89,649 +50,6 @@ enum LanguageId LANGUAGE_GERMAN = 5, }; -// capacities of various saveblock objects -#define DAYCARE_MON_COUNT 2 -#define POKEBLOCKS_COUNT 40 -#define PARTY_SIZE 6 -#define EVENT_OBJECTS_COUNT 16 -#define BERRY_TREES_COUNT 128 -#define FLAGS_COUNT 288 -#define VARS_COUNT 256 -#define MAIL_COUNT 16 -#define SECRET_BASES_COUNT 20 -#define TV_SHOWS_COUNT 25 -#define POKE_NEWS_COUNT 16 -#define PC_ITEMS_COUNT 50 -#define BAG_ITEMS_COUNT 20 -#define BAG_KEYITEMS_COUNT 20 -#define BAG_POKEBALLS_COUNT 16 -#define BAG_TMHM_COUNT 64 -#define BAG_BERRIES_COUNT 46 - -enum -{ - MALE, - FEMALE -}; - -enum -{ - OPTIONS_BUTTON_MODE_NORMAL, - OPTIONS_BUTTON_MODE_LR, - OPTIONS_BUTTON_MODE_L_EQUALS_A -}; - -enum -{ - OPTIONS_TEXT_SPEED_SLOW, - OPTIONS_TEXT_SPEED_MID, - OPTIONS_TEXT_SPEED_FAST -}; - -enum -{ - OPTIONS_SOUND_MONO, - OPTIONS_SOUND_STEREO -}; - -enum -{ - OPTIONS_BATTLE_STYLE_SHIFT, - OPTIONS_BATTLE_STYLE_SET -}; - -enum -{ - BAG_ITEMS = 1, - BAG_POKEBALLS, - BAG_TMsHMs, - BAG_BERRIES, - BAG_KEYITEMS -}; - -struct Coords16 -{ - s16 x; - s16 y; -}; - -struct UCoords16 -{ - u16 x; - u16 y; -}; - -struct SecretBaseRecord -{ - /*0x1A08*/ u8 secretBaseId; - /*0x1A09*/ u8 sbr_field_1_0:4; - /*0x1A09*/ u8 gender:1; - /*0x1A09*/ u8 sbr_field_1_5:1; - /*0x1A09*/ u8 sbr_field_1_6:2; - /*0x1A0A*/ u8 playerName[OT_NAME_LENGTH]; - /*0x1A11*/ u8 trainerId[4]; // byte 0 is used for determining trainer class - /*0x1A16*/ u16 sbr_field_e; - /*0x1A18*/ u8 sbr_field_10; - /*0x1A19*/ u8 sbr_field_11; - /*0x1A1A*/ u8 decorations[16]; - /*0x1A2A*/ u8 decorationPos[16]; - /*0x1A3C*/ u32 partyPersonality[6]; - /*0x1A54*/ u16 partyMoves[6 * 4]; - /*0x1A84*/ u16 partySpecies[6]; - /*0x1A90*/ u16 partyHeldItems[6]; - /*0x1A9C*/ u8 partyLevels[6]; - /*0x1AA2*/ u8 partyEVs[6]; -}; - -#include "constants/game_stat.h" -#include "global.fieldmap.h" -#include "global.berry.h" -#include "pokemon.h" - -struct WarpData -{ - s8 mapGroup; - s8 mapNum; - s8 warpId; - s16 x, y; -}; - -struct ItemSlot -{ - u16 itemId; - u16 quantity; -}; - -struct Pokeblock -{ - u8 color; - u8 spicy; - u8 dry; - u8 sweet; - u8 bitter; - u8 sour; - u8 feel; -}; - -struct Roamer -{ - /*0x00*/ u32 ivs; - /*0x04*/ u32 personality; - /*0x08*/ u16 species; - /*0x0A*/ u16 hp; - /*0x0C*/ u8 level; - /*0x0D*/ u8 status; - /*0x0E*/ u8 cool; - /*0x0F*/ u8 beauty; - /*0x10*/ u8 cute; - /*0x11*/ u8 smart; - /*0x12*/ u8 tough; - /*0x13*/ bool8 active; - /*0x14*/ u8 filler[0x8]; -}; - -struct RamScriptData -{ - u8 magic; - u8 mapGroup; - u8 mapNum; - u8 objectId; - u8 script[995]; -}; - -struct RamScript -{ - u32 checksum; - struct RamScriptData data; -}; - -struct EasyChatPair -{ - u16 unk0_0:7; - u16 unk0_7:7; - u16 unk1_6:1; - u16 unk2; - u16 words[2]; -}; /*size = 0x8*/ - -struct TVShowCommon -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 pad02[20]; - /*0x16*/ u16 var16[3]; - /*0x1C*/ u8 srcTrainerId3Lo; - /*0x1D*/ u8 srcTrainerId3Hi; - /*0x1E*/ u8 srcTrainerId2Lo; - /*0x1F*/ u8 srcTrainerId2Hi; - /*0x20*/ u8 srcTrainerIdLo; - /*0x21*/ u8 srcTrainerIdHi; - /*0x22*/ u8 trainerIdLo; - /*0x23*/ u8 trainerIdHi; -}; - -struct TVShowFanClubLetter -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u16 species; - /*0x04*/ u16 pad04[6]; - /*0x10*/ u8 playerName[8]; - /*0x18*/ u8 language; -}; - -struct TVShowRecentHappenings -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u16 var02; - /*0x04*/ u16 var04[6]; - /*0x10*/ u8 playerName[8]; - /*0x18*/ u8 language; - /*0x19*/ u8 pad19[10]; -}; - -struct TVShowFanclubOpinions -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u16 var02; - /*0x04*/ u8 var04A:4; - /*0x04*/ u8 var04B:4; - /*0x05*/ u8 playerName[8]; - /*0x0D*/ u8 language; - /*0x0E*/ u8 var0E; - /*0x0F*/ u8 var0F; - /*0x10*/ u8 var10[8]; - /*0x18*/ u16 var18[2]; - /*0x1C*/ u16 var1C[4]; -}; - -struct TVShowUnknownType04 -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 pad02[4]; - /*0x06*/ u16 var06; -}; - -struct TVShowNameRaterShow -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u16 species; - /*0x04*/ u8 pokemonName[11]; - /*0x0F*/ u8 trainerName[11]; - /*0x1A*/ u8 random; - /*0x1B*/ u8 random2; - /*0x1C*/ u16 var1C; - /*0x1E*/ u8 language; - /*0x1F*/ u8 pokemonNameLanguage; -}; - -struct TVShowBravoTrainerPokemonProfiles -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u16 species; - /*0x04*/ u16 var04[2]; - /*0x08*/ u8 pokemonNickname[11]; - /*0x13*/ u8 contestCategory:3; - /*0x13*/ u8 contestRank:2; - /*0x13*/ u8 contestResult:2; - /*0x13*/ u8 var13_7:1; - /*0x14*/ u16 var14; - /*0x16*/ u8 playerName[8]; - /*0x1E*/ u8 language; - /*0x1F*/ u8 var1f; -}; - -struct TVShowBravoTrainerBattleTowerSpotlight -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 trainerName[8]; - /*0x0A*/ u16 species; - /*0x0C*/ u8 enemyTrainerName[8]; - /*0x14*/ u16 defeatedSpecies; - /*0x16*/ u16 var16; - /*0x18*/ u16 var18[1]; - /*0x1A*/ u8 btLevel; - /*0x1B*/ u8 var1b; - /*0x1C*/ u8 var1c; - /*0x1D*/ u8 language; -}; - -struct TVShowPokemonToday -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 language; - /*0x03*/ u8 language2; - /*0x04*/ u8 nickname[11]; - /*0x0F*/ u8 ball; - /*0x10*/ u16 species; - /*0x12*/ u8 var12; - /*0x13*/ u8 playerName[8]; -}; - -struct TVShowSmartShopper -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 priceReduced; - /*0x03*/ u8 language; - /*0x04*/ u8 pad04[2]; - /*0x06*/ u16 itemIds[3]; - /*0x0C*/ u16 itemAmounts[3]; - /*0x12*/ u8 shopLocation; - /*0x13*/ u8 playerName[8]; -}; - -struct TVShowPokemonTodayFailed -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 language; - /*0x03*/ u8 pad03[9]; - /*0x0c*/ u16 species; - /*0x0e*/ u16 species2; - /*0x10*/ u8 var10; - /*0x11*/ u8 var11; - /*0x12*/ u8 var12; - /*0x13*/ u8 playerName[8]; -}; - -struct TVShowPokemonAngler -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 var02; - /*0x03*/ u8 var03; - /*0x04*/ u16 var04; - /*0x06*/ u8 language; - u8 pad07[12]; - /*0x13*/ u8 playerName[8]; -}; - -struct TVShowWorldOfMasters -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u16 var02; - /*0x04*/ u16 var04; - /*0x06*/ u16 var06; - /*0x08*/ u16 var08; - /*0x0a*/ u8 var0a; - /*0x0b*/ u8 language; - u8 pad0c[7]; - /*0x13*/ u8 playerName[8]; -}; - -struct TVShowMassOutbreak -{ - /*0x00*/ u8 kind; - /*0x01*/ bool8 active; - /*0x02*/ u8 var02; - /*0x03*/ u8 var03; - /*0x04*/ u16 moves[4]; - /*0x0C*/ u16 species; - /*0x0E*/ u16 var0E; - /*0x10*/ u8 locationMapNum; - /*0x11*/ u8 locationMapGroup; - /*0x12*/ u8 var12; - /*0x13*/ u8 probability; - /*0x14*/ u8 level; - /*0x15*/ u8 var15; - /*0x16*/ u16 daysLeft; - /*0x18*/ u8 language; - u8 pad19[11]; -}; - -typedef union TVShow -{ - struct TVShowCommon common; - struct TVShowFanClubLetter fanclubLetter; - struct TVShowRecentHappenings recentHappenings; - struct TVShowFanclubOpinions fanclubOpinions; - struct TVShowUnknownType04 unkShow04; - struct TVShowNameRaterShow nameRaterShow; - struct TVShowBravoTrainerPokemonProfiles bravoTrainer; - struct TVShowBravoTrainerBattleTowerSpotlight bravoTrainerTower; - struct TVShowPokemonToday pokemonToday; - struct TVShowSmartShopper smartshopperShow; - struct TVShowPokemonTodayFailed pokemonTodayFailed; - struct TVShowPokemonAngler pokemonAngler; - struct TVShowWorldOfMasters worldOfMasters; - struct TVShowMassOutbreak massOutbreak; -} TVShow; - -struct MailStruct -{ - /*0x00*/ u16 words[9]; - /*0x12*/ u8 playerName[8]; - /*0x1A*/ u8 trainerId[4]; - /*0x1E*/ u16 species; - /*0x20*/ u16 itemId; -}; - - -// Mauville Pokemon Center men - -struct MauvilleManCommon -{ - u8 id; -}; - -struct MauvilleManBard -{ - /*0x00*/ u8 id; - /*0x02*/ u16 songLyrics[6]; - /*0x0E*/ u16 temporaryLyrics[6]; - /*0x1A*/ u8 playerName[8]; - /*0x22*/ u8 filler_2DB6[0x3]; - /*0x25*/ u8 playerTrainerId[4]; - /*0x29*/ bool8 hasChangedSong; -}; /*size = 0x2C*/ - -struct MauvilleManHipster -{ - u8 id; - bool8 alreadySpoken; -}; - -struct MauvilleManTrader -{ - u8 id; - u8 unk1[4]; - u8 unk5[4][11]; - bool8 alreadyTraded; -}; - -struct MauvilleManStoryteller -{ - u8 id; - bool8 alreadyRecorded; - u8 filler2[2]; - u8 gameStatIDs[4]; - u8 trainerNames[4][7]; - u8 statValues[4][4]; -}; - -struct MauvilleManGiddy -{ - /*0x00*/ u8 id; - /*0x01*/ u8 taleCounter; - /*0x02*/ u8 questionNum; - /*0x04*/ u16 randomWords[10]; - /*0x18*/ u8 questionList[12]; -}; /*size = 0x2C*/ - - -union MauvilleMan -{ - struct MauvilleManCommon common; - struct MauvilleManBard bard; - struct MauvilleManHipster hipster; - struct MauvilleManTrader trader; - struct MauvilleManStoryteller storyteller; - struct MauvilleManGiddy giddy; - u8 filler[0x40]; // needed to pad out the struct -}; - -struct PokeNews -{ - u8 kind; - u8 state; - u16 days; -}; - -struct GabbyAndTyData -{ - /*2b10*/ u16 mon1; - /*2b12*/ u16 mon2; - /*2b14*/ u16 lastMove; - /*2b16*/ u16 quote; - /*2b18*/ u8 mapnum; - /*2b19*/ u8 battleNum; - /*2b1a*/ u8 valA_0:1; - /*2b1a*/ u8 valA_1:1; - /*2b1a*/ u8 valA_2:1; - /*2b1a*/ u8 valA_3:1; - /*2b1a*/ u8 valA_4:1; - /*2b1a*/ u8 valA_5:3; - /*2b1b*/ u8 valB_0:1; - /*2b1b*/ u8 valB_1:1; - /*2b1b*/ u8 valB_2:1; - /*2b1b*/ u8 valB_3:1; - /*2b1b*/ u8 valB_4:1; - /*2b1b*/ u8 valB_5:3; -}; - -struct DayCareMail -{ - /*0x00*/ struct MailStruct message; - /*0x24*/ u8 names[19]; -}; - -struct DayCareStepCountersEtc { - u32 steps[DAYCARE_MON_COUNT]; - u16 pendingEggPersonality; - u8 eggCycleStepsRemaining; -}; - -struct RecordMixingDayCareMail -{ - struct DayCareMail mail[DAYCARE_MON_COUNT]; - u32 numDaycareMons; - u16 itemsHeld[DAYCARE_MON_COUNT]; // marks whether or not each daycare mon is currently holding an item. -}; - -struct DayCareMisc -{ - struct DayCareMail mail[DAYCARE_MON_COUNT]; - struct DayCareStepCountersEtc countersEtc; -}; - -struct DayCare { - struct BoxPokemon mons[DAYCARE_MON_COUNT]; - struct DayCareMisc misc; -}; - -struct LinkBattleRecord -{ - u8 name[8]; - u16 trainerId; - u16 wins; - u16 losses; - u16 draws; -}; - -struct RecordMixingGiftData -{ - u8 unk0; - u8 quantity; - u16 itemId; - u8 filler4[8]; -}; - -struct RecordMixingGift -{ - int checksum; - struct RecordMixingGiftData data; -}; - -struct ContestWinner -{ - /*0x00*/ u32 personality; // personality - /*0x04*/ u32 otId; // otId - /*0x08*/ u16 species; // species - /*0x0A*/ u8 contestCategory; - /*0x0B*/ u8 nickname[11]; - /*0x16*/ u8 trainerName[8]; -}; - -// there should be enough flags for all 412 slots -// each slot takes up 8 flags -// if the value is not divisible by 8, we need to account for the reminder as well -#define DEX_FLAGS_NO ((POKEMON_SLOTS_NUMBER / 8) + ((POKEMON_SLOTS_NUMBER % 8) ? 1 : 0)) - -struct SaveBlock1 /* 0x02025734 */ -{ - /*0x00*/ struct Coords16 pos; - /*0x04*/ struct WarpData location; - /*0x0C*/ struct WarpData warp1; - /*0x14*/ struct WarpData warp2; - /*0x1C*/ struct WarpData lastHealLocation; - /*0x24*/ struct WarpData warp4; - /*0x2C*/ u16 savedMusic; - /*0x2E*/ u8 weather; - /*0x2F*/ u8 weatherCycleStage; - /*0x30*/ u8 flashLevel; // flash level on current map, 0 being normal and 4 being the darkest - /*0x32*/ u16 mapLayoutId; - /*0x34*/ u16 mapView[0x100]; - /*0x234*/ u8 playerPartyCount; - /*0x238*/ struct Pokemon playerParty[6]; - /*0x490*/ u32 money; - /*0x494*/ u16 coins; - /*0x496*/ u16 registeredItem; // registered for use with SELECT button - /*0x498*/ struct ItemSlot pcItems[PC_ITEMS_COUNT]; - /*0x560*/ struct ItemSlot bagPocket_Items[BAG_ITEMS_COUNT]; - /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[BAG_KEYITEMS_COUNT]; - /*0x600*/ struct ItemSlot bagPocket_PokeBalls[BAG_POKEBALLS_COUNT]; - /*0x640*/ struct ItemSlot bagPocket_TMHM[BAG_TMHM_COUNT]; - /*0x740*/ struct ItemSlot bagPocket_Berries[BAG_BERRIES_COUNT]; - /*0x7F8*/ struct Pokeblock pokeblocks[POKEBLOCKS_COUNT]; - /*0x938*/ u8 dexSeen2[DEX_FLAGS_NO]; - /*0x96C*/ u16 berryBlenderRecords[3]; - /*0x972*/ u8 filler_972[0x6]; - /*0x978*/ u16 trainerRematchStepCounter; - /*0x97A*/ u8 trainerRematches[100]; - /*0x9E0*/ struct EventObject eventObjects[EVENT_OBJECTS_COUNT]; - /*0xC20*/ struct EventObjectTemplate eventObjectTemplates[64]; - /*0x1220*/ u8 flags[FLAGS_COUNT]; - /*0x1340*/ u16 vars[VARS_COUNT]; - /*0x1540*/ u32 gameStats[NUM_GAME_STATS]; - /*0x1608*/ struct BerryTree berryTrees[BERRY_TREES_COUNT]; - /*0x1A08*/ struct SecretBaseRecord secretBases[SECRET_BASES_COUNT]; - /*0x2688*/ u8 playerRoomDecor[12]; - /*0x2694*/ u8 playerRoomDecorPos[12]; - /*0x26A0*/ u8 decorDesk[10]; - /*0x26AA*/ u8 decorChair[10]; - /*0x26B4*/ u8 decorPlant[10]; - /*0x26BE*/ u8 decorOrnament[30]; - /*0x26DC*/ u8 decorMat[30]; - /*0x26FA*/ u8 decorPoster[10]; - /*0x2704*/ u8 decorDoll[40]; - /*0x272C*/ u8 decorCushion[10]; - /*0x2736*/ u8 padding_2736[2]; - /*0x2738*/ TVShow tvShows[TV_SHOWS_COUNT]; - /*0x2ABC*/ struct PokeNews pokeNews[POKE_NEWS_COUNT]; - /*0x2AFC*/ u16 outbreakPokemonSpecies; - /*0x2AFE*/ u8 outbreakLocationMapNum; - /*0x2AFF*/ u8 outbreakLocationMapGroup; - /*0x2B00*/ u8 outbreakPokemonLevel; - /*0x2B01*/ u8 outbreakUnk1; - /*0x2B02*/ u16 outbreakUnk2; - /*0x2B04*/ u16 outbreakPokemonMoves[4]; - /*0x2B0C*/ u8 outbreakUnk4; - /*0x2B0D*/ u8 outbreakPokemonProbability; - /*0x2B0E*/ u16 outbreakUnk5; - /*0x2B10*/ struct GabbyAndTyData gabbyAndTyData; - /*0x2B1C*/ struct { - /*0x2B1C*/ u16 unk2B1C[6]; - /*0x2B28*/ u16 unk2B28[6]; - /*0x2B34*/ u16 unk2B34[6]; - /*0x2B40*/ u16 unk2B40[6]; - } easyChats; - /*0x2B4C*/ struct MailStruct mail[MAIL_COUNT]; - /*0x2D8C*/ u8 unk2D8C[4]; // What is this? Apparently it's supposed to be 64 bytes in size. - /*0x2D90*/ u8 filler_2D90[0x4]; - /*0x2D94*/ union MauvilleMan mauvilleMan; - /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff - /*0x2DFC*/ struct ContestWinner contestWinners[8]; - /*0x2EFC*/ struct ContestWinner museumPortraits[5]; - /*0x2F9C*/ struct DayCare daycare; - /*0x30B8*/ struct LinkBattleRecord linkBattleRecords[5]; - struct { - /*0x3108*/ u8 unknown1[8]; - /*0x3110*/ u8 giftRibbons[11]; - /*0x311B*/ u8 unknown2[8]; - /*0x3123*/ u32 currentPokeCoupons; - /*0x3127*/ u32 totalEarnedPokeCoupons; - /*0x312B*/ u8 unknown3[6]; - /*0x3131*/ u8 receivedWishmakerJirachi; - /*0x3132*/ u8 unknown4[18]; - } __attribute__((packed)) externalReservedData; - /*0x3144*/ struct Roamer roamer; - /*0x3160*/ struct EnigmaBerry enigmaBerry; - /*0x3690*/ struct RamScript ramScript; - /*0x3A7C*/ struct RecordMixingGift recordMixingGift; - /*0x3A8C*/ u8 dexSeen3[DEX_FLAGS_NO]; -}; - -extern struct SaveBlock1 gSaveBlock1; - struct Time { /*0x00*/ s16 days; @@ -740,137 +58,27 @@ struct Time /*0x04*/ s8 seconds; }; -struct Pokedex -{ - /*0x00*/ u8 order; - /*0x01*/ u8 unknown1; - /*0x02*/ u8 nationalMagic; // must equal 0xDA in order to have National mode - /*0x03*/ u8 unknown2; - /*0x04*/ u32 unownPersonality; // set when you first see Unown - /*0x08*/ u32 spindaPersonality; // set when you first see Spinda - /*0x0C*/ u32 unknown3; - /*0x10*/ u8 owned[DEX_FLAGS_NO]; - /*0x44*/ u8 seen[DEX_FLAGS_NO]; -}; +// Dummy Ruby/Sapphire save structs. +// Only the vars array in SaveBlock1 is needed for the Berry Fix Program. -struct BattleTowerTrainer +struct SaveBlock1 { - /*0x00*/ u8 trainerClass; - /*0x01*/ u8 name[8]; - /*0x09*/ u8 teamFlags; - u8 filler0A[2]; - /*0x0C*/ u16 greeting[6]; + u8 dummy_PreVars[0x1340]; + u16 vars[VARS_COUNT]; + u8 dummy_PostVars[0x2580]; }; +extern struct SaveBlock1 gSaveBlock1; -struct BattleTowerRecord // record mixing +struct SaveBlock2 { - /*0x00*/ u8 battleTowerLevelType; // 0 = level 50, 1 = level 100 - /*0x01*/ u8 trainerClass; - /*0x02*/ u16 winStreak; - /*0x04*/ u8 name[8]; - /*0x0C*/ u8 trainerId[4]; - /*0x10*/ u16 greeting[6]; - /*0x1C*/ struct BattleTowerPokemon party[3]; - /*0xA0*/ u32 checksum; + u8 dummy[0x890]; }; - -struct BattleTowerEReaderTrainer -{ - /*0x00*/ u8 unk0; - /*0x01*/ u8 trainerClass; - /*0x02*/ u16 winStreak; - /*0x04*/ u8 name[8]; - /*0x0C*/ u8 trainerId[4]; - /*0x10*/ u16 greeting[6]; - /*0x1C*/ u16 farewellPlayerLost[6]; - /*0x28*/ u16 farewellPlayerWon[6]; - /*0x34*/ struct BattleTowerPokemon party[3]; - /*0xB8*/ u32 checksum; -}; - -struct BattleTowerData -{ - /*0x0000, 0x00A8*/ struct BattleTowerRecord playerRecord; - /*0x00A4, 0x014C*/ struct BattleTowerRecord records[5]; // from record mixing - /*0x03D8, 0x0480*/ u16 firstMonSpecies; // species of the first pokemon in the player's battle tower party - /*0x03DA, 0x0482*/ u16 defeatedBySpecies; // species of the pokemon that defated the player - /*0x03DC, 0x0484*/ u8 defeatedByTrainerName[8]; - /*0x03E4, 0x048C*/ u8 firstMonNickname[POKEMON_NAME_LENGTH]; // nickname of the first pokemon in the player's battle tower party - /*0x03F0, 0x0498*/ struct BattleTowerEReaderTrainer ereaderTrainer; - /*0x04AC, 0x0554*/ u8 battleTowerLevelType:1; // 0 = level 50; 1 = level 100 - /*0x04AC, 0x0554*/ u8 unk_554:1; - /*0x04AD, 0x0555*/ u8 battleOutcome; - /*0x04AE, 0x0556*/ u8 var_4AE[2]; - /*0x04B0, 0x0558*/ u16 curChallengeBattleNum[2]; // 1-based index of battle in the current challenge. (challenges consist of 7 battles) - /*0x04B4, 0x055C*/ u16 curStreakChallengesNum[2]; // 1-based index of the current challenge in the current streak. - /*0x04B8, 0x0560*/ u16 recordWinStreaks[2]; - /*0x04BC, 0x0564*/ u8 battleTowerTrainerId; // index for gBattleTowerTrainers table - /*0x04BD, 0x0565*/ u8 selectedPartyMons[0x3]; // indices of the 3 selected player party mons. - /*0x04C0, 0x0568*/ u16 prizeItem; - /*0x04C2, 0x056A*/ u8 battledTrainerIds[6]; - /*0x04C8, 0x0570*/ u16 totalBattleTowerWins; - /*0x04CA, 0x0572*/ u16 bestBattleTowerWinStreak; - /*0x04CC, 0x0574*/ u16 currentWinStreaks[2]; - /*0x04D0, 0x0578*/ u8 lastStreakLevelType; // 0 = level 50, 1 = level 100. level type of the last streak. Used by tv to report the level mode. - /*0x04D1, 0x0579*/ u8 filler_4D1[0x317]; -}; - -struct SaveBlock2 /* 0x02024EA4 */ -{ - /*0x00*/ u8 playerName[8]; - /*0x08*/ u8 playerGender; // MALE, FEMALE - /*0x09*/ u8 specialSaveWarp; - /*0x0A*/ u8 playerTrainerId[4]; - /*0x0E*/ u16 playTimeHours; - /*0x10*/ u8 playTimeMinutes; - /*0x11*/ u8 playTimeSeconds; - /*0x12*/ u8 playTimeVBlanks; - /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A] - /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST] - u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes - u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO] - u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET] - u16 optionsBattleSceneOff:1; // whether battle animations are disabled - u16 regionMapZoom:1; // whether the map is zoomed in - /*0x18*/ struct Pokedex pokedex; - /*0x90*/ u8 filler_90[0x8]; - /*0x98*/ struct Time localTimeOffset; - /*0xA0*/ struct Time lastBerryTreeUpdate; - /*0xA8*/ struct BattleTowerData battleTower; -}; - -struct MapPosition -{ - s16 x; - s16 y; - s8 height; -}; - -struct UnkStruct_8054FF8 -{ - u8 a; - u8 b; - u8 c; - u8 d; - struct MapPosition sub; - u16 field_C; -}; - -// wasnt defined so I had to define it -struct HallOfFame -{ - u8 filler[0x1F00]; -}; - extern struct SaveBlock2 gSaveBlock2; -#define RomHeaderGameTitle ((const char *)0x080000A0) -#define RomHeaderGameCode ((const char *)0x080000AC) -#define RomHeaderMakerCode ((const char *)0x080000B0) -#define RomHeaderMagic ((const u8 *) 0x080000B2) -#define RomHeaderSoftwareVersion ((const u8 *) 0x080000BC) - -#define LocalTimeOffset ((struct Time *)0x02028098) -#define LastBerryTreeUpdate ((struct Time *)0x020280A0) +struct PokemonStorage +{ + u8 dummy[0x83D0]; +}; +extern struct PokemonStorage gPokemonStorage; #endif //GUARD_GLOBAL_H diff --git a/payload/include/pokemon.h b/payload/include/pokemon.h deleted file mode 100644 index d3a14ff..0000000 --- a/payload/include/pokemon.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef GUARD_POKEMON_H -#define GUARD_POKEMON_H - -struct PokemonSubstruct0 -{ - u16 species; - u16 heldItem; - u32 experience; - u8 ppBonuses; - u8 friendship; -}; - -struct PokemonSubstruct1 -{ - u16 moves[4]; - u8 pp[4]; -}; - -struct PokemonSubstruct2 -{ - u8 hpEV; - u8 attackEV; - u8 defenseEV; - u8 speedEV; - u8 spAttackEV; - u8 spDefenseEV; - u8 cool; - u8 beauty; - u8 cute; - u8 smart; - u8 tough; - u8 sheen; -}; - -struct PokemonSubstruct3 -{ - /*0x00*/ u8 pokerus; - /*0x01*/ u8 metLocation; - - /*0x02*/ u16 metLevel:7; - /*0x02*/ u16 metGame:4; - /*0x03*/ u16 pokeball:4; - /*0x03*/ u16 otGender:1; - - /*0x04*/ u32 hpIV:5; - /*0x04*/ u32 attackIV:5; - /*0x05*/ u32 defenseIV:5; - /*0x05*/ u32 speedIV:5; - /*0x05*/ u32 spAttackIV:5; - /*0x06*/ u32 spDefenseIV:5; - /*0x07*/ u32 isEgg:1; - /*0x07*/ u32 altAbility:1; - - /*0x08*/ u32 coolRibbon:3; - /*0x08*/ u32 beautyRibbon:3; - /*0x08*/ u32 cuteRibbon:3; - /*0x09*/ u32 smartRibbon:3; - /*0x09*/ u32 toughRibbon:3; - /*0x09*/ u32 championRibbon:1; - /*0x0A*/ u32 winningRibbon:1; - /*0x0A*/ u32 victoryRibbon:1; - /*0x0A*/ u32 artistRibbon:1; - /*0x0A*/ u32 effortRibbon:1; - /*0x0A*/ u32 giftRibbon1:1; - /*0x0A*/ u32 giftRibbon2:1; - /*0x0A*/ u32 giftRibbon3:1; - /*0x0A*/ u32 giftRibbon4:1; - /*0x0B*/ u32 giftRibbon5:1; - /*0x0B*/ u32 giftRibbon6:1; - /*0x0B*/ u32 giftRibbon7:1; - /*0x0B*/ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald -}; - -union PokemonSubstruct -{ - struct PokemonSubstruct0 type0; - struct PokemonSubstruct1 type1; - struct PokemonSubstruct2 type2; - struct PokemonSubstruct3 type3; - u16 raw[6]; -}; - -struct BoxPokemon -{ - /*0x00*/ u32 personality; - /*0x04*/ u32 otId; - /*0x08*/ u8 nickname[POKEMON_NAME_LENGTH]; - /*0x12*/ u8 language; - /*0x13*/ u8 isBadEgg:1; - u8 hasSpecies:1; - u8 isEgg:1; - /*0x14*/ u8 otName[OT_NAME_LENGTH]; - /*0x1B*/ u8 markings; - /*0x1C*/ u16 checksum; - /*0x1E*/ u16 unknown; - - union - { - u32 raw[12]; - union PokemonSubstruct substructs[4]; - } secure; -}; /*size = 0x50*/ - -struct Pokemon -{ - /*0x00*/ struct BoxPokemon box; - /*0x50*/ u32 status; - /*0x54*/ u8 level; - /*0x55*/ u8 mail; - /*0x56*/ u16 hp; - /*0x58*/ u16 maxHP; - /*0x5A*/ u16 attack; - /*0x5C*/ u16 defense; - /*0x5E*/ u16 speed; - /*0x60*/ u16 spAttack; - /*0x62*/ u16 spDefense; -}; - -struct BattleTowerPokemon -{ - /*0x00*/u16 species; - /*0x02*/u16 heldItem; - /*0x04*/u16 moves[4]; - /*0x0C*/u8 level; - /*0x0D*/u8 ppBonuses; - /*0x0E*/u8 hpEV; - /*0x0F*/u8 attackEV; - /*0x10*/u8 defenseEV; - /*0x11*/u8 speedEV; - /*0x12*/u8 spAttackEV; - /*0x13*/u8 spDefenseEV; - /*0x14*/u32 otId; - /*0x18*/u32 hpIV:5; - /*0x18*/u32 attackIV:5; - /*0x19*/u32 defenseIV:5; - /*0x19*/u32 speedIV:5; - /*0x1A*/u32 spAttackIV:5; - /*0x1A*/u32 spDefenseIV:5; - /*0x1B*/u32 gap:1; - /*0x1B*/u32 altAbility:1; - /*0x1C*/u32 personality; - /*0x20*/u8 nickname[POKEMON_NAME_LENGTH + 1]; - /*0x2B*/u8 friendship; -}; - -struct PokemonStorage -{ - /*0x0000*/ u8 currentBox; - /*0x0004*/ struct BoxPokemon boxes[14][30]; - /*0x8344*/ u8 boxNames[14][9]; - /*0x83c2*/ u8 wallpaper[14]; -}; - -#endif // GUARD_POKEMON_H From 43d0fa817e4ba199a35181d58e963b355ce553f7 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:30:01 -0500 Subject: [PATCH 03/12] Pare down more headers, some save sync --- payload/include/constants/vars.h | 193 +----------- payload/include/flash.h | 55 ---- payload/include/gba/gba.h | 2 +- payload/include/gba/isagbprint.h | 50 --- payload/include/gba/m4a_internal.h | 467 ----------------------------- payload/include/global.h | 4 +- payload/include/save.h | 77 +++++ payload/ld_script.txt | 4 +- payload/src/agb_flash.c | 1 - payload/src/agb_flash_1m.c | 1 - payload/src/agb_flash_le.c | 1 - payload/src/agb_flash_mx.c | 1 - payload/src/main.c | 2 +- payload/src/{flash.c => save.c} | 235 ++++++++------- payload/sym_bss.txt | 4 +- payload/sym_common.txt | 4 +- payload/sym_ewram.txt | 2 +- 17 files changed, 209 insertions(+), 894 deletions(-) delete mode 100644 payload/include/flash.h delete mode 100644 payload/include/gba/isagbprint.h delete mode 100644 payload/include/gba/m4a_internal.h create mode 100644 payload/include/save.h rename payload/src/{flash.c => save.c} (69%) diff --git a/payload/include/constants/vars.h b/payload/include/constants/vars.h index 4b40c1d..0b95ea0 100644 --- a/payload/include/constants/vars.h +++ b/payload/include/constants/vars.h @@ -1,196 +1,11 @@ #ifndef GUARD_CONSTANTS_VARS_H #define GUARD_CONSTANTS_VARS_H -#define VAR_0x3F20 0x3F20 +#define VARS_START 0x4000 +#define SPECIAL_VARS_START 0x8000 -#define VARS_START 0x4000 +#define VARS_COUNT 256 -// temporary vars -// The first 0x10 vars are are temporary--they are cleared every time a map is loaded. -#define VAR_TEMP_0 0x4000 -#define VAR_TEMP_1 0x4001 -#define VAR_TEMP_2 0x4002 -#define VAR_TEMP_3 0x4003 -#define VAR_TEMP_4 0x4004 -#define VAR_TEMP_5 0x4005 -#define VAR_TEMP_6 0x4006 -#define VAR_TEMP_7 0x4007 -#define VAR_TEMP_8 0x4008 -#define VAR_TEMP_9 0x4009 -#define VAR_TEMP_A 0x400A -#define VAR_TEMP_B 0x400B -#define VAR_TEMP_C 0x400C -#define VAR_TEMP_D 0x400D -#define VAR_TEMP_E 0x400E -#define VAR_TEMP_F 0x400F - -// object gfx id vars -// These 0x10 vars are used to dynamically control a event object's sprite. -// For example, the rival's sprite id is dynamically set based on the player's gender. -// See VarGetEventObjectGraphicsId(). -#define VAR_OBJ_GFX_ID_0 0x4010 -#define VAR_OBJ_GFX_ID_1 0x4011 -#define VAR_OBJ_GFX_ID_2 0x4012 -#define VAR_OBJ_GFX_ID_3 0x4013 -#define VAR_OBJ_GFX_ID_4 0x4014 -#define VAR_OBJ_GFX_ID_5 0x4015 -#define VAR_OBJ_GFX_ID_6 0x4016 -#define VAR_OBJ_GFX_ID_7 0x4017 -#define VAR_OBJ_GFX_ID_8 0x4018 -#define VAR_OBJ_GFX_ID_9 0x4019 -#define VAR_OBJ_GFX_ID_A 0x401A -#define VAR_OBJ_GFX_ID_B 0x401B -#define VAR_OBJ_GFX_ID_C 0x401C -#define VAR_OBJ_GFX_ID_D 0x401D -#define VAR_OBJ_GFX_ID_E 0x401E -#define VAR_OBJ_GFX_ID_F 0x401F - -// general purpose vars -#define VAR_RECYCLE_GOODS 0x4020 -#define VAR_REPEL_STEP_COUNT 0x4021 -#define VAR_ICE_STEP_COUNT 0x4022 -#define VAR_STARTER_MON 0x4023 // 0=Treecko, 1=Torchic, 2=Mudkip -#define VAR_MIRAGE_RND_H 0x4024 -#define VAR_MIRAGE_RND_L 0x4025 -#define VAR_SECRET_BASE_MAP 0x4026 -#define VAR_CYCLING_ROAD_RECORD_COLLISIONS 0x4027 -#define VAR_CYCLING_ROAD_RECORD_TIME_L 0x4028 -#define VAR_CYCLING_ROAD_RECORD_TIME_H 0x4029 -#define VAR_HAPPINESS_STEP_COUNTER 0x402A -#define VAR_POISON_STEP_COUNTER 0x402B -#define VAR_RESET_RTC_ENABLE 0x402C -#define VAR_ENIGMA_BERRY_AVAILABLE 0x402D - -#define VAR_DAYS 0x4040 -#define VAR_FANCLUB_UNKNOWN_1 0x4041 // TODO: document these two fanclub vars -#define VAR_FANCLUB_UNKNOWN_2 0x4042 -#define VAR_DEPT_STORE_FLOOR 0x4043 -#define VAR_TRICK_HOUSE_ROOMS_COMPLETED 0x4044 -#define VAR_LOTTERY_PRIZE 0x4045 -#define VAR_NATIONAL_DEX 0x4046 -#define VAR_SHROOMISH_SIZE_RECORD 0x4047 -#define VAR_ASH_GATHER_COUNT 0x4048 -#define VAR_BIRCH_STATE 0x4049 -#define VAR_CRUISE_STEP_COUNT 0x404A -#define VAR_LOTTERY_RND_L 0x404B -#define VAR_LOTTERY_RND_H 0x404C - -#define VAR_BARBOACH_SIZE_RECORD 0x404F -#define VAR_LITTLEROOT_STATE 0x4050 -#define VAR_ROUTE102_ACCESSIBLE 0x4051 - -#define VAR_LAVARIDGE_RIVAL_STATE 0x4053 -#define VAR_CURRENT_SECRET_BASE 0x4054 - -#define VAR_PETALBURG_STATE 0x4057 -#define VAR_SLATEPORT_STATE 0x4058 - -#define VAR_RUSTBORO_STATE 0x405A - -#define VAR_SOOTOPOLIS_STATE 0x405E - -#define VAR_ROUTE101_STATE 0x4060 - -#define VAR_ROUTE103_STATE 0x4062 - -#define VAR_ROUTE110_STATE 0x4069 - -#define VAR_ROUTE116_STATE 0x406F - -#define VAR_ROUTE118_STATE 0x4071 -#define VAR_ROUTE119_STATE 0x4072 - -#define VAR_ROUTE121_STATE 0x4074 -#define VAR_ROUTE128_STATE 0x407B - -#define VAR_LITTLEROOT_HOUSES_STATE 0x4082 // TODO: needs more investigation - -#define VAR_BIRCH_LAB_STATE 0x4084 -#define VAR_PETALBURG_GYM_STATE 0x4085 -#define VAR_LINK_CONTEST_ROOM_STATE 0x4086 -#define VAR_CABLE_CLUB_STATE 0x4087 -#define VAR_CONTEST_LOCATION 0x4088 -#define VAR_MAP_SCENE_SIX_ISLAND_POKEMON_CENTER_1F 0x4089 // TODO: related to decorations -#define VAR_CONTEST_PRIZE_PICKUP 0x408A - -#define VAR_LITTLEROOT_HOUSES_STATE_2 0x408C // TODO: needs more investigation -#define VAR_LITTLEROOT_RIVAL_STATE 0x408D -#define VAR_BOARD_BRINEY_BOAT_ROUTE104_STATE 0x408E -#define VAR_DEVON_CORP_3F_STATE 0x408F -#define VAR_BRINEY_HOUSE_STATE 0x4090 - -#define VAR_LITTLEROOT_INTRO_STATE 0x4092 -#define VAR_MAUVILLE_GYM_STATE 0x4093 -#define VAR_LILYCOVE_MUSEUM_2F_STATE 0x4094 -#define VAR_LILYCOVE_FAN_CLUB_STATE 0x4095 -#define VAR_BRINEY_LOCATION 0x4096 -#define VAR_0x4097 0x4097 // TODO: related to creating new secret base -#define VAR_PETALBURG_WOODS_STATE 0x4098 -#define VAR_LILYCOVE_CONTEST_LOBBY_STATE 0x4099 -#define VAR_RUSTURF_TUNNEL_STATE 0x409a -#define VAR_CAVE_OF_ORIGIN_B4F_STATE 0x409B -#define VAR_ELITE_4_STATE 0x409C - -#define VAR_SLATEPORT_HARBOR_STATE 0x40A0 - -#define VAR_SEAFLOOR_CAVERN_STATE 0x40A2 -#define VAR_CABLE_CAR_STATION_STATE 0x40A3 -#define VAR_SAFARI_ZONE_STATE 0x40A4 -#define VAR_TRICK_HOUSE_ENTRANCE_STATE 0x40A5 -#define VAR_TRICK_HOUSE_ENTRANCE_STATE_2 0x40A6 -#define VAR_TRICK_HOUSE_ENTRANCE_STATE_3 0x40A7 - -#define VAR_CYCLING_CHALLENGE_STATE 0x40A9 -#define VAR_SLATEPORT_MUSEUM_1F_STATE 0x40AA -#define VAR_TRICK_HOUSE_PUZZLE_1_STATE 0x40AB -#define VAR_TRICK_HOUSE_PUZZLE_2_STATE 0x40AC -#define VAR_TRICK_HOUSE_PUZZLE_3_STATE 0x40AD -#define VAR_TRICK_HOUSE_PUZZLE_4_STATE 0x40AE -#define VAR_TRICK_HOUSE_PUZZLE_5_STATE 0x40AF -#define VAR_TRICK_HOUSE_PUZZLE_6_STATE 0x40B0 -#define VAR_TRICK_HOUSE_PUZZLE_7_STATE 0x40B1 -#define VAR_TRICK_HOUSE_PUZZLE_8_STATE 0x40B2 -#define VAR_WEATHER_INSTITUTE_STATE 0x40B3 -#define VAR_PORTHOLE_STATE 0x40B4 -#define VAR_TRICK_HOUSE_STATE 0x40B5 // TODO: needs some further investigation -#define VAR_TRICK_HOUSE_PUZZLE_7_STATE_2 0x40B6 -#define VAR_SLATEPORT_FAN_CLUB_STATE 0x40B7 - -#define VAR_MT_PYRE_STATE 0x40B9 -#define VAR_NEW_MAUVILLE_STATE 0x40BA - -#define VAR_BRAVO_TRAINER_BATTLE_TOWER_ON 0x40BC -#define VAR_JAGGED_PASS_VOLCANIC_ASH_WEATHER 0x40BD -#define VAR_GLASS_WORKSHOP_STATE 0x40BE -#define VAR_METEOR_FALLS_STATE 0x40BF -#define VAR_GAME_CORNER_STATE 0x40C0 -#define VAR_TRICK_HOUSE_PRIZE_PICKUP 0x40C1 -#define VAR_PACIFIDLOG_TM_RECEIVED_DAY 0x40C2 -#define VAR_VICTORY_ROAD_1F_STATE 0x40C3 -#define VAR_FOSSIL_RESURRECTION_STATE 0x40C4 -#define VAR_WHICH_FOSSIL_REVIVED 0x40C5 -#define VAR_STEVENS_HOUSE_STATE 0x40C6 -#define VAR_OLDALE_STATE 0x40C7 - -// special vars -// They are commonly used as parameters to commands, or return values from commands. -#define VAR_SPECIAL_0 0x8000 -#define VAR_SPECIAL_1 0x8001 -#define VAR_SPECIAL_2 0x8002 -#define VAR_SPECIAL_3 0x8003 -#define VAR_SPECIAL_4 0x8004 -#define VAR_SPECIAL_5 0x8005 -#define VAR_SPECIAL_6 0x8006 -#define VAR_SPECIAL_7 0x8007 -#define VAR_SPECIAL_8 0x8008 -#define VAR_SPECIAL_9 0x8009 -#define VAR_SPECIAL_A 0x800A -#define VAR_SPECIAL_B 0x800B -#define FACING 0x800C -#define RESULT 0x800D -#define ITEM_ID 0x800E -#define LAST_TALKED 0x800F -#define CONTEST_RANK 0x8010 -#define CONTEST_CATEGORY 0x8011 +#define VAR_PACIFIDLOG_TM_RECEIVED_DAY 0x40C2 #endif // GUARD_CONSTANTS_VARS_H diff --git a/payload/include/flash.h b/payload/include/flash.h deleted file mode 100644 index 7fc3589..0000000 --- a/payload/include/flash.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GUARD_FLASH_H -#define GUARD_FLASH_H - -#include "gba/gba.h" - -enum -{ - SECTOR_DAMAGED, - SECTOR_OK, - SECTOR_CHECK, // unused -}; - -enum MsgBoxUpdateMessage -{ - MSGBOX_WILL_NOW_UPDATE = 0, - MSGBOX_HAS_BEEN_UPDATED, - MSGBOX_UNABLE_TO_UPDATE, - MSGBOX_NO_NEED_TO_UPDATE, - MSGBOX_UPDATING -}; - -struct SaveSector -{ - u8 data[0xFF4]; - u16 id; - u16 checksum; - u32 signature; - u32 counter; -}; // size is 0x1000 - -// headless save section? -struct UnkSaveSection -{ - u8 data[0xFF4]; - u32 signature; -}; // size is 0xFF8 - -#define eSaveSection ((struct SaveSector *)0x2020000) - -#define NUM_SECTORS_PER_SAVE_SLOT 14 // Number of sectors occupied by a save slot -#define FILE_SIGNATURE 0x08012025 - -#define SAVE_STATUS_EMPTY 0 -#define SAVE_STATUS_OK 1 -#define SAVE_STATUS_NO_FLASH 4 -#define SAVE_STATUS_ERROR 0xFF - -bool32 flash_maincb_ident_is_valid(void); -bool8 flash_maincb_read_save(u32); -void msg_load_gfx(void); -void msg_display(enum MsgBoxUpdateMessage); -bool32 flash_maincb_check_need_reset_pacifidlog_tm(void); -bool32 flash_maincb_reset_pacifidlog_tm(void); - -#endif //GUARD_FLASH_H diff --git a/payload/include/gba/gba.h b/payload/include/gba/gba.h index 3493440..a4606f1 100644 --- a/payload/include/gba/gba.h +++ b/payload/include/gba/gba.h @@ -7,6 +7,6 @@ #include "gba/multiboot.h" #include "gba/syscall.h" #include "gba/macro.h" -#include "gba/isagbprint.h" +#include "gba/flash_internal.h" #endif // GUARD_GBA_GBA_H diff --git a/payload/include/gba/isagbprint.h b/payload/include/gba/isagbprint.h deleted file mode 100644 index c5eb456..0000000 --- a/payload/include/gba/isagbprint.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef GUARD_GBA_ISAGBPRINT_H -#define GUARD_GBA_ISAGBPRINT_H - -#ifdef NDEBUG -#define AGBPrintInit() -#define AGBPutc(cChr) -#define AGBPrint(pBuf) -#define AGBPrintf(pBuf, ...) -#define AGBPrintFlush1Block() -#define AGBPrintFlush() -#define AGBAssert(pFile, nLine, pExpression, nStopProgram) -#else -void AGBPrintInit(void); -void AGBPutc(const char cChr); -void AGBPrint(const char *pBuf); -void AGBPrintf(const char *pBuf, ...); -void AGBPrintFlush1Block(void); -void AGBPrintFlush(void); -void AGBAssert(const char *pFile, int nLine, const char *pExpression, int nStopProgram); -#endif - -#undef AGB_ASSERT -#ifdef NDEBUG -#define AGB_ASSERT(exp) -#else -#define AGB_ASSERT(exp) (exp) ? ((void*)0) : AGBAssert(__FILE__, __LINE__, #exp, 1); -#endif - -#undef AGB_WARNING -#ifdef NDEBUG -#define AGB_WARNING(exp) -#else -#define AGB_WARNING(exp) (exp) ? ((void*)0) : AGBAssert(__FILE__, __LINE__, #exp, 0); -#endif - -// for matching purposes - -#ifdef NDEBUG -#define AGB_ASSERT_EX(exp, file, line) -#else -#define AGB_ASSERT_EX(exp, file, line) (exp) ? ((void*)0) : AGBAssert(file, line, #exp, 1); -#endif - -#ifdef NDEBUG -#define AGB_WARNING_EX(exp, file, line) -#else -#define AGB_WARNING_EX(exp, file, line) (exp) ? ((void*)0) : AGBAssert(file, line, #exp, 0); -#endif - -#endif // GUARD_GBA_ISAGBPRINT_H diff --git a/payload/include/gba/m4a_internal.h b/payload/include/gba/m4a_internal.h deleted file mode 100644 index 1aca675..0000000 --- a/payload/include/gba/m4a_internal.h +++ /dev/null @@ -1,467 +0,0 @@ -#ifndef GUARD_GBA_M4A_INTERNAL_H -#define GUARD_GBA_M4A_INTERNAL_H - -#include "gba/gba.h" - -// ASCII encoding of 'Smsh' in reverse -// This is presumably short for SMASH, the developer of MKS4AGB. -#define ID_NUMBER 0x68736D53 - -#define C_V 0x40 // center value for PAN, BEND, and TUNE - -#define SOUND_MODE_REVERB_VAL 0x0000007F -#define SOUND_MODE_REVERB_SET 0x00000080 -#define SOUND_MODE_MAXCHN 0x00000F00 -#define SOUND_MODE_MAXCHN_SHIFT 8 -#define SOUND_MODE_MASVOL 0x0000F000 -#define SOUND_MODE_MASVOL_SHIFT 12 -#define SOUND_MODE_FREQ_05734 0x00010000 -#define SOUND_MODE_FREQ_07884 0x00020000 -#define SOUND_MODE_FREQ_10512 0x00030000 -#define SOUND_MODE_FREQ_13379 0x00040000 -#define SOUND_MODE_FREQ_15768 0x00050000 -#define SOUND_MODE_FREQ_18157 0x00060000 -#define SOUND_MODE_FREQ_21024 0x00070000 -#define SOUND_MODE_FREQ_26758 0x00080000 -#define SOUND_MODE_FREQ_31536 0x00090000 -#define SOUND_MODE_FREQ_36314 0x000A0000 -#define SOUND_MODE_FREQ_40137 0x000B0000 -#define SOUND_MODE_FREQ_42048 0x000C0000 -#define SOUND_MODE_FREQ 0x000F0000 -#define SOUND_MODE_FREQ_SHIFT 16 -#define SOUND_MODE_DA_BIT_9 0x00800000 -#define SOUND_MODE_DA_BIT_8 0x00900000 -#define SOUND_MODE_DA_BIT_7 0x00A00000 -#define SOUND_MODE_DA_BIT_6 0x00B00000 -#define SOUND_MODE_DA_BIT 0x00B00000 -#define SOUND_MODE_DA_BIT_SHIFT 20 - -struct WaveData -{ - u16 type; - u16 status; - u32 freq; - u32 loopStart; - u32 size; // number of samples - s8 data[1]; // samples -}; - -#define TONEDATA_TYPE_CGB 0x07 -#define TONEDATA_TYPE_FIX 0x08 -#define TONEDATA_TYPE_SPL 0x40 // key split -#define TONEDATA_TYPE_RHY 0x80 // rhythm - -#define TONEDATA_P_S_PAN 0xc0 -#define TONEDATA_P_S_PAM TONEDATA_P_S_PAN - -struct ToneData -{ - u8 type; - u8 key; - u8 length; // sound length (compatible sound) - u8 pan_sweep; // pan or sweep (compatible sound ch. 1) - struct WaveData *wav; - u8 attack; - u8 decay; - u8 sustain; - u8 release; -}; - -struct CgbChannel -{ - u8 sf; - u8 ty; - u8 rightVolume; - u8 leftVolume; - u8 at; - u8 de; - u8 su; - u8 re; - u8 ky; - u8 ev; - u8 eg; - u8 ec; - u8 echoVolume; - u8 echoLength; - u8 d1; - u8 d2; - u8 gt; - u8 mk; - u8 ve; - u8 pr; - u8 rp; - u8 d3[3]; - u8 d5; - u8 sg; - u8 n4; - u8 pan; - u8 panMask; - u8 mo; - u8 le; - u8 sw; - u32 fr; - u32 wp; - u32 cp; - u32 tp; - u32 pp; - u32 np; - u8 d4[8]; -}; - -struct MusicPlayerTrack; - -struct SoundChannel -{ - u8 status; - u8 type; - u8 rightVolume; - u8 leftVolume; - u8 attack; - u8 decay; - u8 sustain; - u8 release; - u8 ky; - u8 ev; - u8 er; - u8 el; - u8 echoVolume; - u8 echoLength; - u8 d1; - u8 d2; - u8 gt; - u8 mk; - u8 ve; - u8 pr; - u8 rp; - u8 d3[3]; - u32 ct; - u32 fw; - u32 freq; - struct WaveData *wav; - u32 cp; - struct MusicPlayerTrack *track; - u32 pp; - u32 np; - u32 d4; - u16 xpi; - u16 xpc; -}; - -#define MAX_DIRECTSOUND_CHANNELS 12 - -#define PCM_DMA_BUF_SIZE 1584 // size of Direct Sound buffer - -struct SoundInfo -{ - // This field is normally equal to ID_NUMBER but it is set to other - // values during sensitive operations for locking purposes. - // This field should be volatile but isn't. This could potentially cause - // race conditions. - u32 ident; - - vu8 pcmDmaCounter; - - // Direct Sound - u8 reverb; - u8 maxChans; - u8 masterVolume; - u8 freq; - - u8 mode; - u8 c15; - u8 pcmDmaPeriod; // number of V-blanks per PCM DMA - u8 maxLines; - u8 gap[3]; - s32 pcmSamplesPerVBlank; - s32 pcmFreq; - s32 divFreq; - struct CgbChannel *cgbChans; - u32 func; - u32 intp; - void (*CgbSound)(void); - void (*CgbOscOff)(u8); - u32 (*MidiKeyToCgbFreq)(u8, u8, u8); - u32 MPlayJumpTable; - u32 plynote; - u32 ExtVolPit; - u8 gap2[16]; - struct SoundChannel chans[MAX_DIRECTSOUND_CHANNELS]; - s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; -}; - -struct SongHeader -{ - u8 trackCount; - u8 blockCount; - u8 priority; - u8 reverb; - struct ToneData *tone; - u8 *part[1]; -}; - -struct PokemonCrySong -{ - u8 trackCount; - u8 blockCount; - u8 priority; - u8 reverb; - struct ToneData *tone; - u8 *part[2]; - u8 gap; - u8 part0; // 0x11 - u8 tuneValue; // 0x12 - u8 gotoCmd; // 0x13 - u32 gotoTarget; // 0x14 - u8 part1; // 0x18 - u8 tuneValue2; // 0x19 - u8 cont[2]; // 0x1A - u8 volCmd; // 0x1C - u8 volumeValue; // 0x1D - u8 unkCmd0D[2]; // 0x1E - u32 unkCmd0DParam; // 0x20 - u8 xreleCmd[2]; // 0x24 - u8 releaseValue; // 0x26 - u8 panCmd; - u8 panValue; // 0x28 - u8 tieCmd; // 0x29 - u8 tieKeyValue; // 0x2A - u8 tieVelocityValue; // 0x2B - u8 unkCmd0C[2]; // 0x2C - u16 unkCmd0CParam; // 0x2E - u8 end[2]; // 0x30 -}; - -#define MPT_FLG_VOLSET 0x01 -#define MPT_FLG_VOLCHG 0x03 -#define MPT_FLG_PITSET 0x04 -#define MPT_FLG_PITCHG 0x0C -#define MPT_FLG_START 0x40 -#define MPT_FLG_EXIST 0x80 - -struct MusicPlayerTrack -{ - u8 flags; - u8 wait; - u8 patternLevel; - u8 repN; - u8 gateTime; - u8 key; - u8 velocity; - u8 runningStatus; - u8 keyM; - u8 pitM; - s8 keyShift; - s8 keyShiftX; - s8 tune; - u8 pitX; - s8 bend; - u8 bendRange; - u8 volMR; - u8 volML; - u8 vol; - u8 volX; - s8 pan; - s8 panX; - s8 modM; - u8 mod; - u8 modT; - u8 lfoSpeed; - u8 lfoSpeedC; - u8 lfoDelay; - u8 lfoDelayC; - u8 priority; - u8 echoVolume; - u8 echoLength; - struct SoundChannel *chan; - struct ToneData tone; - u8 gap[10]; - u16 unk_3A; - u32 unk_3C; - u8 *cmdPtr; - u8 *patternStack[3]; -}; - -#define MUSICPLAYER_STATUS_TRACK 0x0000ffff -#define MUSICPLAYER_STATUS_PAUSE 0x80000000 - -#define MAX_MUSICPLAYER_TRACKS 16 - -#define TEMPORARY_FADE 0x0001 -#define FADE_IN 0x0002 -#define FADE_VOL_MAX 64 -#define FADE_VOL_SHIFT 2 - -struct MusicPlayerInfo -{ - struct SongHeader *songHeader; - u32 status; - u8 trackCount; - u8 priority; - u8 cmd; - u8 unk_B; - u32 clock; - u8 gap[8]; - u8 *memAccArea; - u16 tempoD; - u16 tempoU; - u16 tempoI; - u16 tempoC; - u16 fadeOI; - u16 fadeOC; - u16 fadeOV; - struct MusicPlayerTrack *tracks; - struct ToneData *tone; - u32 ident; - u32 func; - u32 intp; -}; - -struct MusicPlayer -{ - struct MusicPlayerInfo *info; - struct MusicPlayerTrack *track; - u8 unk_8; - u16 unk_A; -}; - -struct Song -{ - struct SongHeader *header; - u16 ms; - u16 me; -}; - -extern const struct MusicPlayer gMPlayTable[]; -extern const struct Song gSongTable[]; - - - -extern u8 gMPlayMemAccArea[]; - -//u8 gPokemonCrySong[52]; -//u8 gPokemonCrySongs[52 * MAX_POKEMON_CRIES]; - -#define MAX_POKEMON_CRIES 2 - -extern struct PokemonCrySong gPokemonCrySong; -extern struct PokemonCrySong gPokemonCrySongs[]; - -extern struct MusicPlayerInfo gPokemonCryMusicPlayers[]; -extern struct MusicPlayerTrack gPokemonCryTracks[]; - -extern char SoundMainRAM[]; - -extern void *gMPlayJumpTable[]; - -typedef void (*XcmdFunc)(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -extern const XcmdFunc gXcmdTable[]; - -extern struct CgbChannel gCgbChans[]; - -extern const u8 gScaleTable[]; -extern const u32 gFreqTable[]; -extern const u16 gPcmSamplesPerVBlankTable[]; - -extern const u8 gCgbScaleTable[]; -extern const s16 gCgbFreqTable[]; -extern const u8 gNoiseTable[]; - -extern const struct PokemonCrySong gPokemonCrySongTemplate; - -extern const struct ToneData voicegroup000; - -extern char gNumMusicPlayers[]; -extern char gMaxLines[]; - -#define NUM_MUSIC_PLAYERS ((u16)gNumMusicPlayers) -#define MAX_LINES ((u32)gMaxLines) - -u32 umul3232H32(u32 multiplier, u32 multiplicand); -void SoundMain(void); -void SoundMainBTM(void); -void TrackStop(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track); -void MPlayMain(void); -void RealClearChain(void *x); - -void MPlayContinue(struct MusicPlayerInfo *mplayInfo); -void MPlayStart(struct MusicPlayerInfo *mplayInfo, struct SongHeader *songHeader); -void m4aMPlayStop(struct MusicPlayerInfo *mplayInfo); -void FadeOutBody(struct MusicPlayerInfo *mplayInfo); -void TrkVolPitSet(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track); -void MPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed); -void ClearChain(void *x); -void Clear64byte(void *addr); -void SoundInit(struct SoundInfo *soundInfo); -void MPlayExtender(struct CgbChannel *cgbChans); -void m4aSoundMode(u32 mode); -void MPlayOpen(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track, u8 a3); -void CgbSound(void); -void CgbOscOff(u8); -u32 MidiKeyToCgbFreq(u8, u8, u8); -void DummyFunc(void); -void MPlayJumpTableCopy(void **mplayJumpTable); -void SampleFreqSet(u32 freq); -void m4aSoundVSyncOn(void); -void m4aSoundVSyncOff(void); - -void m4aMPlayTempoControl(struct MusicPlayerInfo *mplayInfo, u16 tempo); -void m4aMPlayVolumeControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u16 volume); -void m4aMPlayPitchControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s16 pitch); -void m4aMPlayPanpotControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s8 pan); -void ClearModM(struct MusicPlayerTrack *track); -void m4aMPlayModDepthSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 modDepth); -void m4aMPlayLFOSpeedSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 lfoSpeed); - -struct MusicPlayerInfo *SetPokemonCryTone(struct ToneData *tone); -void SetPokemonCryVolume(u8 val); -void SetPokemonCryPanpot(s8 val); -void SetPokemonCryPitch(s16 val); -void SetPokemonCryLength(u16 val); -void SetPokemonCryRelease(u8 val); -void SetPokemonCryProgress(u32 val); -bool32 IsPokemonCryPlaying(struct MusicPlayerInfo *mplayInfo); -void SetPokemonCryChorus(s8 val); -void SetPokemonCryStereo(u32 val); -void SetPokemonCryPriority(u8 val); - -// sound command handler functions -void ply_fine(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_goto(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_patt(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_pend(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_rept(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_memacc(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_prio(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_tempo(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_keysh(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_voice(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_vol(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_pan(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_bend(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_bendr(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_lfos(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_lfodl(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_mod(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_modt(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_tune(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_port(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xcmd(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_endtie(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_note(struct MusicPlayerInfo *, struct MusicPlayerTrack *); - -// extended sound command handler functions -void ply_xxx(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xwave(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xtype(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xatta(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xdeca(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xsust(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xrele(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xiecv(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xiecl(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xleng(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xswee(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xcmd_0C(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xcmd_0D(struct MusicPlayerInfo *, struct MusicPlayerTrack *); - -#endif // GUARD_GBA_M4A_INTERNAL_H diff --git a/payload/include/global.h b/payload/include/global.h index a6bcd6b..9762dd6 100644 --- a/payload/include/global.h +++ b/payload/include/global.h @@ -2,6 +2,7 @@ #define GUARD_GLOBAL_H #include "gba/gba.h" +#include "constants/vars.h" // IDE support #if defined(__APPLE__) || defined(__CYGWIN__) || defined(__INTELLISENSE__) @@ -31,7 +32,6 @@ #define POKEMON_SLOTS_NUMBER 412 #define POKEMON_NAME_LENGTH 10 #define OT_NAME_LENGTH 7 -#define VARS_COUNT 256 #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) >= (b) ? (a) : (b)) @@ -59,7 +59,7 @@ struct Time }; // Dummy Ruby/Sapphire save structs. -// Only the vars array in SaveBlock1 is needed for the Berry Fix Program. +// Only the vars array in SaveBlock1 (for VAR_PACIFIDLOG_TM_RECEIVED_DAY specifically) is needed for the Berry Fix Program. struct SaveBlock1 { diff --git a/payload/include/save.h b/payload/include/save.h new file mode 100644 index 0000000..2a858d1 --- /dev/null +++ b/payload/include/save.h @@ -0,0 +1,77 @@ +#ifndef GUARD_FLASH_H +#define GUARD_FLASH_H + +// Each 4 KiB flash sector contains 3968 bytes of actual data followed by a 128 byte footer. +// Only 12 bytes of the footer are used. +#define SECTOR_DATA_SIZE 3968 +#define SECTOR_FOOTER_SIZE 128 +#define SECTOR_SIZE (SECTOR_DATA_SIZE + SECTOR_FOOTER_SIZE) + +#define NUM_SAVE_SLOTS 2 + +// If the sector's security field is not this value then the sector is either invalid or empty. +#define SECTOR_SECURITY_NUM 0x8012025 + +#define SECTOR_ID_SAVEBLOCK2 0 +#define SECTOR_ID_SAVEBLOCK1_START 1 +#define SECTOR_ID_SAVEBLOCK1_END 4 +#define SECTOR_ID_PKMN_STORAGE_START 5 +#define SECTOR_ID_PKMN_STORAGE_END 13 +#define NUM_SECTORS_PER_SLOT 14 +// Save Slot 1: 0-13; Save Slot 2: 14-27 +#define SECTOR_ID_HOF_1 28 +#define SECTOR_ID_HOF_2 29 +#define SECTOR_ID_TRAINER_HILL 30 +#define SECTOR_ID_RECORDED_BATTLE 31 +#define SECTORS_COUNT 32 + +#define SAVE_STATUS_EMPTY 0 +#define SAVE_STATUS_OK 1 +#define SAVE_STATUS_CORRUPT 2 +#define SAVE_STATUS_NO_FLASH 4 +#define SAVE_STATUS_ERROR 0xFF + +// Special sector id value for certain save functions to +// indicate that no specific sector should be used. +#define FULL_SAVE_SLOT 0xFFFF + +enum +{ + SECTOR_DAMAGED, + SECTOR_OK, + SECTOR_CHECK, // unused +}; + +enum MsgBoxUpdateMessage +{ + MSGBOX_WILL_NOW_UPDATE = 0, + MSGBOX_HAS_BEEN_UPDATED, + MSGBOX_UNABLE_TO_UPDATE, + MSGBOX_NO_NEED_TO_UPDATE, + MSGBOX_UPDATING +}; + +struct SaveSector +{ + u8 data[SECTOR_DATA_SIZE]; + u8 unused[SECTOR_FOOTER_SIZE - 12]; // Unused portion of the footer + u16 id; + u16 checksum; + u32 security; + u32 counter; +}; // size is SECTOR_SIZE (0x1000) + +#define SECTOR_SECURITY_OFFSET offsetof(struct SaveSector, security) +#define SECTOR_COUNTER_OFFSET offsetof(struct SaveSector, counter) + +#define eSaveSection ((struct SaveSector *)0x2020000) + + +bool32 flash_maincb_ident_is_valid(void); +bool8 flash_maincb_read_save(u32); +void msg_load_gfx(void); +void msg_display(enum MsgBoxUpdateMessage); +bool32 flash_maincb_check_need_reset_pacifidlog_tm(void); +bool32 flash_maincb_reset_pacifidlog_tm(void); + +#endif //GUARD_FLASH_H diff --git a/payload/ld_script.txt b/payload/ld_script.txt index d0a0af9..1f0c4c9 100644 --- a/payload/ld_script.txt +++ b/payload/ld_script.txt @@ -9,7 +9,7 @@ SECTIONS { asm/crt0.o(.text); src/main.o(.text); src/rtc.o(.text); - src/flash.o(.text); + src/save.o(.text); } =0 lib_text : @@ -31,7 +31,7 @@ SECTIONS { { src/main.o(.rodata); src/rtc.o(.rodata); - src/flash.o(.rodata); + src/save.o(.rodata); } =0 lib_rodata : diff --git a/payload/src/agb_flash.c b/payload/src/agb_flash.c index 2c2c96e..73f7ed2 100644 --- a/payload/src/agb_flash.c +++ b/payload/src/agb_flash.c @@ -1,5 +1,4 @@ #include "gba/gba.h" -#include "gba/flash_internal.h" static u8 sTimerNum; static u16 sTimerCount; diff --git a/payload/src/agb_flash_1m.c b/payload/src/agb_flash_1m.c index 7f8bdeb..6f3e0fa 100644 --- a/payload/src/agb_flash_1m.c +++ b/payload/src/agb_flash_1m.c @@ -1,5 +1,4 @@ #include "gba/gba.h" -#include "gba/flash_internal.h" static const char AgbLibFlashVersion[] = "FLASH1M_V103"; diff --git a/payload/src/agb_flash_le.c b/payload/src/agb_flash_le.c index 39d956e..22b7835 100644 --- a/payload/src/agb_flash_le.c +++ b/payload/src/agb_flash_le.c @@ -1,5 +1,4 @@ #include "gba/gba.h" -#include "gba/flash_internal.h" const u16 leMaxTime[] = { diff --git a/payload/src/agb_flash_mx.c b/payload/src/agb_flash_mx.c index 68eb00c..cf79874 100644 --- a/payload/src/agb_flash_mx.c +++ b/payload/src/agb_flash_mx.c @@ -1,5 +1,4 @@ #include "gba/gba.h" -#include "gba/flash_internal.h" const u16 mxMaxTime[] = { diff --git a/payload/src/main.c b/payload/src/main.c index 32d90f9..b3c3b5b 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -2,7 +2,7 @@ #include "global.h" #include "main.h" #include "rtc.h" -#include "flash.h" +#include "save.h" static s32 gInitialWaitTimer; IntrFunc gIntrTable[16]; diff --git a/payload/src/flash.c b/payload/src/save.c similarity index 69% rename from payload/src/flash.c rename to payload/src/save.c index 1f09d0b..e71db7e 100644 --- a/payload/src/flash.c +++ b/payload/src/save.c @@ -1,9 +1,6 @@ -#include "gba/gba.h" -#include "gba/flash_internal.h" -#include "constants/vars.h" #include "global.h" #include "main.h" -#include "flash.h" +#include "save.h" #include "rtc.h" struct SaveBlockChunk @@ -12,22 +9,22 @@ struct SaveBlockChunk u16 size; }; -u8 WriteSaveBlockChunks(u16 a0, const struct SaveBlockChunk * a1); -u8 WriteSingleChunk(u16 a0, const struct SaveBlockChunk * a1); +u8 WriteSaveBlockChunks(u16, const struct SaveBlockChunk *); +u8 WriteSingleChunk(u16, const struct SaveBlockChunk *); u8 TryWriteSector(u8, u8 *); -u8 EraseCurrentChunk(u16 a0, const struct SaveBlockChunk * a1); -u8 TryReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1); -u8 ReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1); -u8 GetSaveValidStatus(const struct SaveBlockChunk * a1); -u32 DoReadFlashWholeSection(u8 a0, struct SaveSector * a1); +static u8 HandleReplaceSector(u16, const struct SaveBlockChunk *); +u8 TryReadAllSaveSectorsCurrentSlot(u16, const struct SaveBlockChunk *); +u8 ReadAllSaveSectorsCurrentSlot(u16, const struct SaveBlockChunk *); +u8 GetSaveValidStatus(const struct SaveBlockChunk *); +u32 DoReadFlashWholeSection(u8, struct SaveSector *); u16 CalculateChecksum(const void *, u16); -u16 gFirstSaveSector; +u16 gLastWrittenSector; u32 gPrevSaveCounter; u16 gLastKnownGoodSector; u32 gDamagedSaveSectors; u32 gSaveCounter; -struct SaveSector * gFastSaveSection; +struct SaveSector * gReadWriteSector; u16 gCurSaveChunk; bool32 gFlashIdentIsValid; @@ -35,10 +32,6 @@ EWRAM_DATA struct SaveBlock2 gSaveBlock2 = {}; EWRAM_DATA struct SaveBlock1 gSaveBlock1 = {}; EWRAM_DATA struct PokemonStorage gPokemonStorage = {}; -// Each 4 KiB flash sector contains 3968 bytes of actual data followed by a 128 byte footer -#define SECTOR_DATA_SIZE 3968 -#define SECTOR_FOOTER_SIZE 128 - #define SAVEBLOCK_CHUNK(structure, chunkNum) \ { \ (u8 *)&structure + chunkNum * SECTOR_DATA_SIZE, \ @@ -188,7 +181,7 @@ void Save_EraseAllData(void) void Save_ResetSaveCounters(void) { gSaveCounter = 0; - gFirstSaveSector = 0; + gLastWrittenSector = 0; gDamagedSaveSectors = 0; } @@ -218,7 +211,7 @@ u8 WriteSaveBlockChunks(u16 chunkId, const struct SaveBlockChunk *chunks) u32 retVal; u16 i; - gFastSaveSection = eSaveSection; + gReadWriteSector = eSaveSection; if (chunkId != 0xFFFF) // write single chunk { @@ -226,21 +219,21 @@ u8 WriteSaveBlockChunks(u16 chunkId, const struct SaveBlockChunk *chunks) } else // write all chunks { - gLastKnownGoodSector = gFirstSaveSector; + gLastKnownGoodSector = gLastWrittenSector; gPrevSaveCounter = gSaveCounter; - gFirstSaveSector++; - gFirstSaveSector %= NUM_SECTORS_PER_SAVE_SLOT; + gLastWrittenSector++; + gLastWrittenSector %= NUM_SECTORS_PER_SLOT; gSaveCounter++; retVal = SAVE_STATUS_OK; - for (i = 0; i < NUM_SECTORS_PER_SAVE_SLOT; i++) + for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) WriteSingleChunk(i, chunks); // Check for any bad sectors if (gDamagedSaveSectors != 0) // skip the damaged sector. { retVal = SAVE_STATUS_ERROR; - gFirstSaveSector = gLastKnownGoodSector; + gLastWrittenSector = gLastKnownGoodSector; gSaveCounter = gPrevSaveCounter; } } @@ -256,26 +249,26 @@ u8 WriteSingleChunk(u16 chunkId, const struct SaveBlockChunk * chunks) u16 chunkSize; // select sector number - sectorNum = chunkId + gFirstSaveSector; - sectorNum %= NUM_SECTORS_PER_SAVE_SLOT; + sectorNum = chunkId + gLastWrittenSector; + sectorNum %= NUM_SECTORS_PER_SLOT; // select save slot - sectorNum += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2); + sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2); chunkData = chunks[chunkId].data; chunkSize = chunks[chunkId].size; // clear save section. for (i = 0; i < sizeof(struct SaveSector); i++) - ((u8 *)gFastSaveSection)[i] = 0; + ((u8 *)gReadWriteSector)[i] = 0; - gFastSaveSection->id = chunkId; - gFastSaveSection->signature = FILE_SIGNATURE; - gFastSaveSection->counter = gSaveCounter; + gReadWriteSector->id = chunkId; + gReadWriteSector->security = SECTOR_SECURITY_NUM; + gReadWriteSector->counter = gSaveCounter; for (i = 0; i < chunkSize; i++) - gFastSaveSection->data[i] = chunkData[i]; - gFastSaveSection->checksum = CalculateChecksum(chunkData, chunkSize); + gReadWriteSector->data[i] = chunkData[i]; + gReadWriteSector->checksum = CalculateChecksum(chunkData, chunkSize); - return TryWriteSector(sectorNum, gFastSaveSection->data); + return TryWriteSector(sectorNum, gReadWriteSector->data); } u8 HandleWriteSectorNBytes(u8 sectorNum, u8 *data, u16 size) @@ -286,7 +279,7 @@ u8 HandleWriteSectorNBytes(u8 sectorNum, u8 *data, u16 size) for (i = 0; i < sizeof(struct SaveSector); i++) ((char *)section)[i] = 0; - section->signature = FILE_SIGNATURE; + section->security = SECTOR_SECURITY_NUM; for (i = 0; i < size; i++) section->data[i] = data[i]; section->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used. @@ -310,11 +303,11 @@ u8 TryWriteSector(u8 sectorNum, u8 *data) u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunk) // chunk is unused { - gFastSaveSection = eSaveSection; - gLastKnownGoodSector = gFirstSaveSector; + gReadWriteSector = eSaveSection; + gLastKnownGoodSector = gLastWrittenSector; gPrevSaveCounter = gSaveCounter; - gFirstSaveSector++; - gFirstSaveSector %= NUM_SECTORS_PER_SAVE_SLOT; + gLastWrittenSector++; + gLastWrittenSector %= NUM_SECTORS_PER_SLOT; gSaveCounter++; gCurSaveChunk = 0; gDamagedSaveSectors = 0; @@ -323,8 +316,8 @@ u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunk) // chu u32 RestoreSaveBackupVars(const struct SaveBlockChunk *chunk) { - gFastSaveSection = eSaveSection; - gLastKnownGoodSector = gFirstSaveSector; + gReadWriteSector = eSaveSection; + gLastKnownGoodSector = gLastWrittenSector; gPrevSaveCounter = gSaveCounter; gCurSaveChunk = 0; gDamagedSaveSectors = 0; @@ -343,7 +336,7 @@ u8 WriteSingleChunkAndIncrement(u16 a1, const struct SaveBlockChunk * chunk) if (gDamagedSaveSectors) { retVal = SAVE_STATUS_ERROR; - gFirstSaveSector = gLastKnownGoodSector; + gLastWrittenSector = gLastKnownGoodSector; gSaveCounter = gPrevSaveCounter; } } @@ -359,18 +352,18 @@ u8 ErasePreviousChunk(u16 a1, const struct SaveBlockChunk *chunk) { u8 retVal = SAVE_STATUS_OK; - EraseCurrentChunk(a1 - 1, chunk); + HandleReplaceSector(a1 - 1, chunk); if (gDamagedSaveSectors) { retVal = SAVE_STATUS_ERROR; - gFirstSaveSector = gLastKnownGoodSector; + gLastWrittenSector = gLastKnownGoodSector; gSaveCounter = gPrevSaveCounter; } return retVal; } -u8 EraseCurrentChunk(u16 chunkId, const struct SaveBlockChunk *chunks) +static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locations) { u16 i; u16 sector; @@ -378,37 +371,38 @@ u8 EraseCurrentChunk(u16 chunkId, const struct SaveBlockChunk *chunks) u16 size; u8 status; - // select sector number - sector = chunkId + gFirstSaveSector; - sector %= NUM_SECTORS_PER_SAVE_SLOT; - // select save slot - sector += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2); + // Adjust sector id for current save slot + sector = sectorId + gLastWrittenSector; + sector %= NUM_SECTORS_PER_SLOT; + sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS); - data = chunks[chunkId].data; - size = chunks[chunkId].size; + // Get current save data + data = locations[sectorId].data; + size = locations[sectorId].size; - // clear temp save section. - for (i = 0; i < sizeof(struct SaveSector); i++) - ((char *)gFastSaveSection)[i] = 0; + // Clear temp save sector. + for (i = 0; i < SECTOR_SIZE; i++) + ((u8 *)gReadWriteSector)[i] = 0; - gFastSaveSection->id = chunkId; - gFastSaveSection->signature = FILE_SIGNATURE; - gFastSaveSection->counter = gSaveCounter; + gReadWriteSector->id = sectorId; + gReadWriteSector->security = SECTOR_SECURITY_NUM; + gReadWriteSector->counter = gSaveCounter; // set temp section's data. for (i = 0; i < size; i++) - gFastSaveSection->data[i] = data[i]; + gReadWriteSector->data[i] = data[i]; // calculate checksum. - gFastSaveSection->checksum = CalculateChecksum(data, size); + gReadWriteSector->checksum = CalculateChecksum(data, size); EraseFlashSector(sector); status = SAVE_STATUS_OK; - for (i = 0; i < sizeof(struct UnkSaveSection); i++) + // Write new save data up to security field + for (i = 0; i < SECTOR_SECURITY_OFFSET; i++) { - if (ProgramFlashByte(sector, i, gFastSaveSection->data[i])) + if (ProgramFlashByte(sector, i, gReadWriteSector->data[i])) { status = SAVE_STATUS_ERROR; break; @@ -417,16 +411,20 @@ u8 EraseCurrentChunk(u16 chunkId, const struct SaveBlockChunk *chunks) if (status == SAVE_STATUS_ERROR) { + // Writing save data failed SetSectorDamagedStatus(SECTOR_DAMAGED, sector); return SAVE_STATUS_ERROR; } else { + // Writing save data succeeded, write security and counter status = SAVE_STATUS_OK; - for (i = 0; i < 7; i++) + // Write security (skipping the first byte) and counter fields. + // The byte of security that is skipped is instead written by WriteSectorSecurityByte or WriteSectorSecurityByte_NoOffset + for (i = 0; i < SECTOR_SIZE - (SECTOR_SECURITY_OFFSET + 1); i++) { - if (ProgramFlashByte(sector, 0xFF9 + i, ((u8 *)gFastSaveSection)[0xFF9 + i])) + if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET + 1 + i, ((u8 *)gReadWriteSector)[SECTOR_SECURITY_OFFSET + 1 + i])) { status = SAVE_STATUS_ERROR; break; @@ -435,32 +433,32 @@ u8 EraseCurrentChunk(u16 chunkId, const struct SaveBlockChunk *chunks) if (status == SAVE_STATUS_ERROR) { + // Writing security/counter failed SetSectorDamagedStatus(SECTOR_DAMAGED, sector); return SAVE_STATUS_ERROR; } else { + // Succeeded SetSectorDamagedStatus(SECTOR_OK, sector); return SAVE_STATUS_OK; } } } -u8 WriteSomeFlashByteToPrevSector(u16 a1, const struct SaveBlockChunk *chunk) +static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *locations) { - u16 sector; + // Adjust sector id for current save slot + u16 sector = sectorId + gLastWrittenSector - 1; + sector %= NUM_SECTORS_PER_SLOT; + sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS); - // select sector number - sector = a1 + gFirstSaveSector - 1; - sector %= NUM_SECTORS_PER_SAVE_SLOT; - // select save slot - sector += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2); - - if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), ((u8 *)gFastSaveSection)[sizeof(struct UnkSaveSection)])) + // Copy just the first byte of the security field from the read/write buffer + if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET, ((u8 *)gReadWriteSector)[SECTOR_SECURITY_OFFSET])) { - // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. + // Sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. SetSectorDamagedStatus(SECTOR_DAMAGED, sector); - gFirstSaveSector = gLastKnownGoodSector; + gLastWrittenSector = gLastKnownGoodSector; gSaveCounter = gPrevSaveCounter; return SAVE_STATUS_ERROR; } @@ -471,24 +469,25 @@ u8 WriteSomeFlashByteToPrevSector(u16 a1, const struct SaveBlockChunk *chunk) } } -u8 WriteSomeFlashByte0x25ToPrevSector(u16 a1, const struct SaveBlockChunk *chunk) +static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *locations) { - u16 sector; + // Adjust sector id for current save slot + u16 sector = sectorId + gLastWrittenSector - 1; + sector %= NUM_SECTORS_PER_SLOT; + sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2); - sector = a1 + gFirstSaveSector - 1; - sector %= NUM_SECTORS_PER_SAVE_SLOT; - sector += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2); - - if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), 0x25)) + // Write just the first byte of the security field, which was skipped by HandleReplaceSector + if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET, SECTOR_SECURITY_NUM & 0xFF)) { - // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. + // Sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. SetSectorDamagedStatus(SECTOR_DAMAGED, sector); - gFirstSaveSector = gLastKnownGoodSector; + gLastWrittenSector = gLastKnownGoodSector; gSaveCounter = gPrevSaveCounter; return SAVE_STATUS_ERROR; } else { + // Succeeded SetSectorDamagedStatus(SECTOR_OK, sector); return SAVE_STATUS_OK; } @@ -497,7 +496,7 @@ u8 WriteSomeFlashByte0x25ToPrevSector(u16 a1, const struct SaveBlockChunk *chunk u8 TryReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunk) { u8 retVal; - gFastSaveSection = eSaveSection; + gReadWriteSector = eSaveSection; if (a1 != 0xFFFF) { retVal = SAVE_STATUS_ERROR; @@ -515,22 +514,22 @@ u8 ReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunks) { u16 i; u16 checksum; - u16 sector = NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2); + u16 sector = NUM_SECTORS_PER_SLOT * (gSaveCounter % 2); u16 id; - for (i = 0; i < NUM_SECTORS_PER_SAVE_SLOT; i++) + for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) { - DoReadFlashWholeSection(i + sector, gFastSaveSection); - id = gFastSaveSection->id; + DoReadFlashWholeSection(i + sector, gReadWriteSector); + id = gReadWriteSector->id; if (id == 0) - gFirstSaveSector = i; - checksum = CalculateChecksum(gFastSaveSection->data, chunks[id].size); - if (gFastSaveSection->signature == FILE_SIGNATURE - && gFastSaveSection->checksum == checksum) + gLastWrittenSector = i; + checksum = CalculateChecksum(gReadWriteSector->data, chunks[id].size); + if (gReadWriteSector->security == SECTOR_SECURITY_NUM + && gReadWriteSector->checksum == checksum) { u16 j; for (j = 0; j < chunks[id].size; j++) - chunks[id].data[j] = gFastSaveSection->data[j]; + chunks[id].data[j] = gReadWriteSector->data[j]; } } @@ -547,22 +546,22 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) u8 slot1Status; u8 slot2Status; u32 validSectors; - const u32 ALL_SECTORS = (1 << NUM_SECTORS_PER_SAVE_SLOT) - 1; // bitmask of all saveblock sectors + const u32 ALL_SECTORS = (1 << NUM_SECTORS_PER_SLOT) - 1; // bitmask of all saveblock sectors // check save slot 1. validSectors = 0; signatureValid = FALSE; - for (sector = 0; sector < NUM_SECTORS_PER_SAVE_SLOT; sector++) + for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++) { - DoReadFlashWholeSection(sector, gFastSaveSection); - if (gFastSaveSection->signature == FILE_SIGNATURE) + DoReadFlashWholeSection(sector, gReadWriteSector); + if (gReadWriteSector->security == SECTOR_SECURITY_NUM) { signatureValid = TRUE; - checksum = CalculateChecksum(gFastSaveSection->data, chunks[gFastSaveSection->id].size); - if (gFastSaveSection->checksum == checksum) + checksum = CalculateChecksum(gReadWriteSector->data, chunks[gReadWriteSector->id].size); + if (gReadWriteSector->checksum == checksum) { - slot1saveCounter = gFastSaveSection->counter; - validSectors |= 1 << gFastSaveSection->id; + slot1saveCounter = gReadWriteSector->counter; + validSectors |= 1 << gReadWriteSector->id; } } } @@ -582,17 +581,17 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) // check save slot 2. validSectors = 0; signatureValid = FALSE; - for (sector = 0; sector < NUM_SECTORS_PER_SAVE_SLOT; sector++) + for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++) { - DoReadFlashWholeSection(NUM_SECTORS_PER_SAVE_SLOT + sector, gFastSaveSection); - if (gFastSaveSection->signature == FILE_SIGNATURE) + DoReadFlashWholeSection(NUM_SECTORS_PER_SLOT + sector, gReadWriteSector); + if (gReadWriteSector->security == SECTOR_SECURITY_NUM) { signatureValid = TRUE; - checksum = CalculateChecksum(gFastSaveSection->data, chunks[gFastSaveSection->id].size); - if (gFastSaveSection->checksum == checksum) + checksum = CalculateChecksum(gReadWriteSector->data, chunks[gReadWriteSector->id].size); + if (gReadWriteSector->checksum == checksum) { - slot2saveCounter = gFastSaveSection->counter; - validSectors |= 1 << gFastSaveSection->id; + slot2saveCounter = gReadWriteSector->counter; + validSectors |= 1 << gReadWriteSector->id; } } } @@ -650,12 +649,12 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) if (slot1Status == SAVE_STATUS_EMPTY && slot2Status == SAVE_STATUS_EMPTY) { gSaveCounter = 0; - gFirstSaveSector = 0; + gLastWrittenSector = 0; return SAVE_STATUS_EMPTY; } gSaveCounter = 0; - gFirstSaveSector = 0; + gLastWrittenSector = 0; return 2; } @@ -665,7 +664,7 @@ u8 ReadSomeUnknownSectorAndVerify(u8 sector, u8 *data, u16 size) struct SaveSector *section = eSaveSection; DoReadFlashWholeSection(sector, section); - if (section->signature == FILE_SIGNATURE) + if (section->security == SECTOR_SECURITY_NUM) { u16 checksum = CalculateChecksum(section->data, size); if (section->id == checksum) @@ -717,19 +716,19 @@ void nullsub_02011834() { } -u16 * get_var_addr(u16 a0) +static u16 * GetVarPointer(u16 id) { - if (a0 < VARS_START) + if (id < VARS_START) return NULL; - if (a0 < VAR_SPECIAL_0) - return &gSaveBlock1.vars[a0 - VARS_START]; + if (id < SPECIAL_VARS_START) + return &gSaveBlock1.vars[id - VARS_START]; return NULL; } bool32 flash_maincb_check_need_reset_pacifidlog_tm(void) { u8 sp0; - u16 * data = get_var_addr(VAR_PACIFIDLOG_TM_RECEIVED_DAY); + u16 * data = GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY); rtc_maincb_is_time_since_last_berry_update_positive(&sp0); if (*data <= gRtcUTCTime.days) return TRUE; @@ -745,7 +744,7 @@ bool32 flash_maincb_reset_pacifidlog_tm(void) rtc_maincb_is_time_since_last_berry_update_positive(&sp0); if (gRtcUTCTime.days < 0) return FALSE; - *get_var_addr(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1; + *GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1; if (flash_write_save_block_chunks_check_damage(0) != TRUE) return FALSE; return TRUE; diff --git a/payload/sym_bss.txt b/payload/sym_bss.txt index 3b1c62a..251eacf 100644 --- a/payload/sym_bss.txt +++ b/payload/sym_bss.txt @@ -1,5 +1,5 @@ .include "src/main.o" .include "src/rtc.o" - .include "src/flash.o" - .include "src/agb_flash.o" + .include "src/save.o" + .include "src/agb_flash.o" .include "src/siirtc.o" diff --git a/payload/sym_common.txt b/payload/sym_common.txt index 28b47f5..4087de6 100644 --- a/payload/sym_common.txt +++ b/payload/sym_common.txt @@ -2,7 +2,7 @@ .include "rtc.o" .align 4 -gFirstSaveSector: @ 0x03001220 +gLastWrittenSector: @ 0x03001220 .space 0x4 gPrevSaveCounter: @ 0x03001224 @@ -17,7 +17,7 @@ gDamagedSaveSectors: @ 0x0300122C gSaveCounter: @ 0x03001230 .space 0x4 -gFastSaveSection: @ 0x03001234 +gReadWriteSector: @ 0x03001234 .space 0x4 gCurSaveChunk: diff --git a/payload/sym_ewram.txt b/payload/sym_ewram.txt index 2c61f5e..0d3fd1d 100644 --- a/payload/sym_ewram.txt +++ b/payload/sym_ewram.txt @@ -1,3 +1,3 @@ .include "src/main.o" .include "src/rtc.o" - .include "src/flash.o" + .include "src/save.o" From df4fa5e88b2109b3fe840a9d1611829c84f0ba11 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:32:46 -0500 Subject: [PATCH 04/12] Sync save --- payload/common_syms/save.txt | 8 + payload/include/save.h | 15 +- payload/src/main.c | 4 +- payload/src/save.c | 420 +++++++++++++++++++---------------- payload/sym_common.txt | 29 +-- 5 files changed, 255 insertions(+), 221 deletions(-) create mode 100644 payload/common_syms/save.txt diff --git a/payload/common_syms/save.txt b/payload/common_syms/save.txt new file mode 100644 index 0000000..d322e94 --- /dev/null +++ b/payload/common_syms/save.txt @@ -0,0 +1,8 @@ +gLastWrittenSector +gLastSaveCounter +gLastKnownGoodSector +gDamagedSaveSectors +gSaveCounter +gReadWriteSector +gIncrementalSectorId +gFlashIdentIsValid diff --git a/payload/include/save.h b/payload/include/save.h index 2a858d1..da3ea2e 100644 --- a/payload/include/save.h +++ b/payload/include/save.h @@ -42,6 +42,13 @@ enum SECTOR_CHECK, // unused }; +enum +{ + SAVE_NORMAL, // Save full save slot + SAVE_SAVEBLOCKS, // Save just SaveBlock1 and SaveBlock2 + SAVE_SAVEBLOCK2, // Save just SaveBlock2 +}; + enum MsgBoxUpdateMessage { MSGBOX_WILL_NOW_UPDATE = 0, @@ -62,13 +69,9 @@ struct SaveSector }; // size is SECTOR_SIZE (0x1000) #define SECTOR_SECURITY_OFFSET offsetof(struct SaveSector, security) -#define SECTOR_COUNTER_OFFSET offsetof(struct SaveSector, counter) -#define eSaveSection ((struct SaveSector *)0x2020000) - - -bool32 flash_maincb_ident_is_valid(void); -bool8 flash_maincb_read_save(u32); +bool32 BerryFix_IdentifyFlash(void); +bool8 BerryFix_LoadSave(u32); void msg_load_gfx(void); void msg_display(enum MsgBoxUpdateMessage); bool32 flash_maincb_check_need_reset_pacifidlog_tm(void); diff --git a/payload/src/main.c b/payload/src/main.c index b3c3b5b..e00db91 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -200,13 +200,13 @@ void main_callback(u32 * state, void * unused1, void * unused2) ++(*state); // MAINCB_CHECK_FLASH break; case MAINCB_CHECK_FLASH: - if (flash_maincb_ident_is_valid() == TRUE) + if (BerryFix_IdentifyFlash() == TRUE) ++(*state); // MAINCB_READ_SAVE else *state = MAINCB_ERROR; break; case MAINCB_READ_SAVE: - if (flash_maincb_read_save(0) == SAVE_STATUS_OK) + if (BerryFix_LoadSave(0) == SAVE_STATUS_OK) ++(*state); // MAINCB_CHECK_TIME else *state = MAINCB_ERROR; diff --git a/payload/src/save.c b/payload/src/save.c index e71db7e..d65d509 100644 --- a/payload/src/save.c +++ b/payload/src/save.c @@ -3,31 +3,38 @@ #include "save.h" #include "rtc.h" +/* + The Berry Fix Program contains a copy of most of Ruby/Sapphire's save code. + Much of it lies unused. +*/ + struct SaveBlockChunk { u8 * data; u16 size; }; -u8 WriteSaveBlockChunks(u16, const struct SaveBlockChunk *); -u8 WriteSingleChunk(u16, const struct SaveBlockChunk *); -u8 TryWriteSector(u8, u8 *); +static u8 WriteSaveSectorOrSlot(u16, const struct SaveBlockChunk *); +static u8 HandleWriteSector(u16, const struct SaveBlockChunk *); +static u8 TryWriteSector(u8, u8 *); static u8 HandleReplaceSector(u16, const struct SaveBlockChunk *); -u8 TryReadAllSaveSectorsCurrentSlot(u16, const struct SaveBlockChunk *); -u8 ReadAllSaveSectorsCurrentSlot(u16, const struct SaveBlockChunk *); -u8 GetSaveValidStatus(const struct SaveBlockChunk *); -u32 DoReadFlashWholeSection(u8, struct SaveSector *); -u16 CalculateChecksum(const void *, u16); +static u8 TryLoadSaveSlot(u16, const struct SaveBlockChunk *); +static u8 CopySaveSlotData(u16, const struct SaveBlockChunk *); +static u8 GetSaveValidStatus(const struct SaveBlockChunk *); +static u32 ReadFlashSector(u8, struct SaveSector *); +static u16 CalculateChecksum(const void *, u16); u16 gLastWrittenSector; -u32 gPrevSaveCounter; +u32 gLastSaveCounter; u16 gLastKnownGoodSector; u32 gDamagedSaveSectors; u32 gSaveCounter; struct SaveSector * gReadWriteSector; -u16 gCurSaveChunk; +u16 gIncrementalSectorId; bool32 gFlashIdentIsValid; +#define gSaveDataBuffer ((struct SaveSector *)(EWRAM_START + 0x20000)) + EWRAM_DATA struct SaveBlock2 gSaveBlock2 = {}; EWRAM_DATA struct SaveBlock1 gSaveBlock1 = {}; EWRAM_DATA struct PokemonStorage gPokemonStorage = {}; @@ -62,7 +69,7 @@ const u16 gInfoMessagesPal[] = INCBIN_U16("graphics/msg_box.gbapal"); const u8 gInfoMessagesTilemap[] = INCBIN_U8("graphics/msg_box.tilemap.lz"); const u8 gInfoMessagesGfx[] = INCBIN_U8("graphics/msg_box.4bpp.lz"); -bool32 flash_maincb_ident_is_valid(void) +bool32 BerryFix_IdentifyFlash(void) { gFlashIdentIsValid = TRUE; if (!IdentifyFlash()) @@ -74,61 +81,59 @@ bool32 flash_maincb_ident_is_valid(void) return FALSE; } -void Call_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size) +// Unused +static void BerryFix_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size) { ReadFlash(sectorNum, offset, dest, size); } -u8 Call_WriteSaveBlockChunks(u16 a0, const struct SaveBlockChunk * a1) +static u8 BerryFix_WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk * chunks) { - return WriteSaveBlockChunks(a0, a1); + return WriteSaveSectorOrSlot(sectorId, chunks); } -u8 Call_TryReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1) +static u8 BerryFix_TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk * chunks) { - return TryReadAllSaveSectorsCurrentSlot(a0, a1); + return TryLoadSaveSlot(sectorId, chunks); } -u32 * GetDamagedSaveSectorsPtr(void) +static u32 * BerryFix_GetDamagedSaveSectors(void) { return &gDamagedSaveSectors; } -s32 flash_write_save_block_chunks(u8 a0) +static s32 BerryFix_Save(u8 mode) { u8 i; - - switch (a0) + switch (mode) { - case 0: - default: - Call_WriteSaveBlockChunks(0xFFFF, sSaveBlockChunks); - break; - case 1: - for (i = 0; i < 5; i++) - { - Call_WriteSaveBlockChunks(i, sSaveBlockChunks); - } - break; - case 2: - Call_WriteSaveBlockChunks(0, sSaveBlockChunks); - break; + case SAVE_NORMAL: + default: + BerryFix_WriteSaveSectorOrSlot(FULL_SAVE_SLOT, sSaveBlockChunks); + break; + case SAVE_SAVEBLOCKS: + for (i = SECTOR_ID_SAVEBLOCK2; i <= SECTOR_ID_SAVEBLOCK1_END; i++) + BerryFix_WriteSaveSectorOrSlot(i, sSaveBlockChunks); + break; + case SAVE_SAVEBLOCK2: + BerryFix_WriteSaveSectorOrSlot(SECTOR_ID_SAVEBLOCK2, sSaveBlockChunks); + break; } return 0; } -u8 flash_write_save_block_chunks_check_damage(u8 a0) +u8 BerryFix_TrySave(u8 mode) { - flash_write_save_block_chunks(a0); - if (*GetDamagedSaveSectorsPtr() == 0) - return 1; - return 0xFF; + BerryFix_Save(mode); + if (*BerryFix_GetDamagedSaveSectors() == 0) + return SAVE_STATUS_OK; + return SAVE_STATUS_ERROR; } -u8 flash_maincb_read_save(u32 unused) +u8 BerryFix_LoadSave(u32 unused) { - return Call_TryReadAllSaveSectorsCurrentSlot(0xFFFF, sSaveBlockChunks); + return BerryFix_TryLoadSaveSlot(FULL_SAVE_SLOT, sSaveBlockChunks); } void msg_load_gfx(void) @@ -139,7 +144,7 @@ void msg_load_gfx(void) REG_BLDCNT = 0; LZ77UnCompVram(gInfoMessagesGfx, (void *)BG_VRAM); LZ77UnCompVram(gInfoMessagesTilemap, (void *)BG_SCREEN_ADDR(28)); - CpuCopy16(gInfoMessagesPal, (void *)BG_PLTT, 0x200); + CpuCopy16(gInfoMessagesPal, (void *)BG_PLTT, BG_PLTT_SIZE); REG_BG0CNT = BGCNT_SCREENBASE(28) | BGCNT_TXT512x512; REG_DISPCNT = DISPCNT_BG0_ON; } @@ -171,199 +176,220 @@ void msg_display(enum MsgBoxUpdateMessage a0) } } -void Save_EraseAllData(void) +// Unused +static void ClearSaveData(void) { u16 i; - for (i = 0; i < 32; i++) + for (i = 0; i < SECTORS_COUNT; i++) EraseFlashSector(i); } -void Save_ResetSaveCounters(void) +// Unused +static void Save_ResetSaveCounters(void) { gSaveCounter = 0; gLastWrittenSector = 0; gDamagedSaveSectors = 0; } -bool32 SetSectorDamagedStatus(u8 op, u8 sectorNum) +static bool32 SetDamagedSectorBits(u8 op, u8 sectorId) { bool32 retVal = FALSE; switch (op) { - case SECTOR_DAMAGED: - gDamagedSaveSectors |= (1 << sectorNum); - break; - case SECTOR_OK: - gDamagedSaveSectors &= ~(1 << sectorNum); - break; - case SECTOR_CHECK: // unused - if (gDamagedSaveSectors & (1 << sectorNum)) - retVal = TRUE; - break; + case SECTOR_DAMAGED: + gDamagedSaveSectors |= (1 << sectorId); + break; + case SECTOR_OK: + gDamagedSaveSectors &= ~(1 << sectorId); + break; + case SECTOR_CHECK: // unused + if (gDamagedSaveSectors & (1 << sectorId)) + retVal = TRUE; + break; } return retVal; } -u8 WriteSaveBlockChunks(u16 chunkId, const struct SaveBlockChunk *chunks) +static u8 WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk *chunks) { - u32 retVal; + u32 status; u16 i; - gReadWriteSector = eSaveSection; + gReadWriteSector = gSaveDataBuffer; - if (chunkId != 0xFFFF) // write single chunk + if (sectorId != FULL_SAVE_SLOT) { - retVal = WriteSingleChunk(chunkId, chunks); + // A sector was specified, just write that sector. + status = HandleWriteSector(sectorId, chunks); } - else // write all chunks + else { + // No sector was specified, write full save slot. gLastKnownGoodSector = gLastWrittenSector; - gPrevSaveCounter = gSaveCounter; + gLastSaveCounter = gSaveCounter; gLastWrittenSector++; gLastWrittenSector %= NUM_SECTORS_PER_SLOT; gSaveCounter++; - retVal = SAVE_STATUS_OK; + status = SAVE_STATUS_OK; for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) - WriteSingleChunk(i, chunks); + HandleWriteSector(i, chunks); - // Check for any bad sectors - if (gDamagedSaveSectors != 0) // skip the damaged sector. + if (gDamagedSaveSectors) { - retVal = SAVE_STATUS_ERROR; + // At least one sector save failed + status = SAVE_STATUS_ERROR; gLastWrittenSector = gLastKnownGoodSector; - gSaveCounter = gPrevSaveCounter; + gSaveCounter = gLastSaveCounter; } } - return retVal; + return status; } -u8 WriteSingleChunk(u16 chunkId, const struct SaveBlockChunk * chunks) +static u8 HandleWriteSector(u16 sectorId, const struct SaveBlockChunk * chunks) { u16 i; u16 sectorNum; - u8 *chunkData; - u16 chunkSize; + u8 *data; + u16 size; - // select sector number - sectorNum = chunkId + gLastWrittenSector; + // Adjust sector id for current save slot + sectorNum = sectorId + gLastWrittenSector; sectorNum %= NUM_SECTORS_PER_SLOT; - // select save slot - sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2); + sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS); - chunkData = chunks[chunkId].data; - chunkSize = chunks[chunkId].size; + // Get current save data + data = chunks[sectorId].data; + size = chunks[sectorId].size; - // clear save section. - for (i = 0; i < sizeof(struct SaveSector); i++) + // Clear temp save sector + for (i = 0; i < SECTOR_SIZE; i++) ((u8 *)gReadWriteSector)[i] = 0; - gReadWriteSector->id = chunkId; + // Set footer data + gReadWriteSector->id = sectorId; gReadWriteSector->security = SECTOR_SECURITY_NUM; gReadWriteSector->counter = gSaveCounter; - for (i = 0; i < chunkSize; i++) - gReadWriteSector->data[i] = chunkData[i]; - gReadWriteSector->checksum = CalculateChecksum(chunkData, chunkSize); + + // Copy current data to temp buffer for writing + for (i = 0; i < size; i++) + gReadWriteSector->data[i] = data[i]; + + gReadWriteSector->checksum = CalculateChecksum(data, size); return TryWriteSector(sectorNum, gReadWriteSector->data); } -u8 HandleWriteSectorNBytes(u8 sectorNum, u8 *data, u16 size) +// Unused +static u8 HandleWriteSectorNBytes(u8 sectorId, u8 *data, u16 size) { u16 i; - struct SaveSector *section = eSaveSection; + struct SaveSector *sector = gSaveDataBuffer; - for (i = 0; i < sizeof(struct SaveSector); i++) - ((char *)section)[i] = 0; + // Clear temp save sector + for (i = 0; i < SECTOR_SIZE; i++) + ((u8 *)sector)[i] = 0; - section->security = SECTOR_SECURITY_NUM; + sector->security = SECTOR_SECURITY_NUM; + + // Copy data to temp buffer for writing for (i = 0; i < size; i++) - section->data[i] = data[i]; - section->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used. + sector->data[i] = data[i]; - return TryWriteSector(sectorNum, section->data); + sector->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used. + return TryWriteSector(sectorId, sector->data); } -u8 TryWriteSector(u8 sectorNum, u8 *data) +static u8 TryWriteSector(u8 sectorNum, u8 *data) { if (ProgramFlashSectorAndVerify(sectorNum, data) != 0) // is damaged? { - SetSectorDamagedStatus(SECTOR_DAMAGED, sectorNum); // set damaged sector bits. + // Failed + SetDamagedSectorBits(SECTOR_DAMAGED, sectorNum); return SAVE_STATUS_ERROR; } else { - SetSectorDamagedStatus(SECTOR_OK, sectorNum); // unset damaged sector bits. it's safe now. + // Succeeded + SetDamagedSectorBits(SECTOR_OK, sectorNum); return SAVE_STATUS_OK; } } -u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunk) // chunk is unused +// Unused +static u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunks) { - gReadWriteSector = eSaveSection; + gReadWriteSector = gSaveDataBuffer; gLastKnownGoodSector = gLastWrittenSector; - gPrevSaveCounter = gSaveCounter; + gLastSaveCounter = gSaveCounter; gLastWrittenSector++; gLastWrittenSector %= NUM_SECTORS_PER_SLOT; gSaveCounter++; - gCurSaveChunk = 0; + gIncrementalSectorId = 0; gDamagedSaveSectors = 0; return 0; } -u32 RestoreSaveBackupVars(const struct SaveBlockChunk *chunk) +// Unused +static u32 RestoreSaveBackupVars(const struct SaveBlockChunk *chunks) { - gReadWriteSector = eSaveSection; + gReadWriteSector = gSaveDataBuffer; gLastKnownGoodSector = gLastWrittenSector; - gPrevSaveCounter = gSaveCounter; - gCurSaveChunk = 0; + gLastSaveCounter = gSaveCounter; + gIncrementalSectorId = 0; gDamagedSaveSectors = 0; return 0; } -u8 WriteSingleChunkAndIncrement(u16 a1, const struct SaveBlockChunk * chunk) +// Unused +static u8 HandleWriteIncrementalSector(u16 numSectors, const struct SaveBlockChunk * chunks) { - u8 retVal; + u8 status; - if (gCurSaveChunk < a1 - 1) + if (gIncrementalSectorId < numSectors - 1) { - retVal = SAVE_STATUS_OK; - WriteSingleChunk(gCurSaveChunk, chunk); - gCurSaveChunk++; + status = SAVE_STATUS_OK; + HandleWriteSector(gIncrementalSectorId, chunks); + gIncrementalSectorId++; if (gDamagedSaveSectors) { - retVal = SAVE_STATUS_ERROR; + status = SAVE_STATUS_ERROR; gLastWrittenSector = gLastKnownGoodSector; - gSaveCounter = gPrevSaveCounter; + gSaveCounter = gLastSaveCounter; } } else { - retVal = SAVE_STATUS_ERROR; + // Exceeded max sector, finished + status = SAVE_STATUS_ERROR; } - return retVal; + return status; } -u8 ErasePreviousChunk(u16 a1, const struct SaveBlockChunk *chunk) +// Unused +static u8 HandleReplaceSectorAndVerify(u16 sectorId, const struct SaveBlockChunk *chunks) { - u8 retVal = SAVE_STATUS_OK; + u8 status = SAVE_STATUS_OK; - HandleReplaceSector(a1 - 1, chunk); + HandleReplaceSector(sectorId - 1, chunks); if (gDamagedSaveSectors) { - retVal = SAVE_STATUS_ERROR; + status = SAVE_STATUS_ERROR; gLastWrittenSector = gLastKnownGoodSector; - gSaveCounter = gPrevSaveCounter; + gSaveCounter = gLastSaveCounter; } - return retVal; + return status; } -static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locations) +// Unused +// Similar to HandleWriteSector, but fully erases the sector first, and skips writing the first security byte +static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *chunks) { u16 i; u16 sector; @@ -377,8 +403,8 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locatio sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS); // Get current save data - data = locations[sectorId].data; - size = locations[sectorId].size; + data = chunks[sectorId].data; + size = chunks[sectorId].size; // Clear temp save sector. for (i = 0; i < SECTOR_SIZE; i++) @@ -412,7 +438,7 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locatio if (status == SAVE_STATUS_ERROR) { // Writing save data failed - SetSectorDamagedStatus(SECTOR_DAMAGED, sector); + SetDamagedSectorBits(SECTOR_DAMAGED, sector); return SAVE_STATUS_ERROR; } else @@ -434,19 +460,20 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locatio if (status == SAVE_STATUS_ERROR) { // Writing security/counter failed - SetSectorDamagedStatus(SECTOR_DAMAGED, sector); + SetDamagedSectorBits(SECTOR_DAMAGED, sector); return SAVE_STATUS_ERROR; } else { // Succeeded - SetSectorDamagedStatus(SECTOR_OK, sector); + SetDamagedSectorBits(SECTOR_OK, sector); return SAVE_STATUS_OK; } } } -static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *locations) +// Unused +static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *chunks) { // Adjust sector id for current save slot u16 sector = sectorId + gLastWrittenSector - 1; @@ -457,19 +484,20 @@ static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *loca if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET, ((u8 *)gReadWriteSector)[SECTOR_SECURITY_OFFSET])) { // Sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. - SetSectorDamagedStatus(SECTOR_DAMAGED, sector); + SetDamagedSectorBits(SECTOR_DAMAGED, sector); gLastWrittenSector = gLastKnownGoodSector; - gSaveCounter = gPrevSaveCounter; + gSaveCounter = gLastSaveCounter; return SAVE_STATUS_ERROR; } else { - SetSectorDamagedStatus(SECTOR_OK, sector); + SetDamagedSectorBits(SECTOR_OK, sector); return SAVE_STATUS_OK; } } -static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *locations) +// Unused +static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *chunks) { // Adjust sector id for current save slot u16 sector = sectorId + gLastWrittenSector - 1; @@ -480,52 +508,57 @@ static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *loc if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET, SECTOR_SECURITY_NUM & 0xFF)) { // Sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. - SetSectorDamagedStatus(SECTOR_DAMAGED, sector); + SetDamagedSectorBits(SECTOR_DAMAGED, sector); gLastWrittenSector = gLastKnownGoodSector; - gSaveCounter = gPrevSaveCounter; + gSaveCounter = gLastSaveCounter; return SAVE_STATUS_ERROR; } else { // Succeeded - SetSectorDamagedStatus(SECTOR_OK, sector); + SetDamagedSectorBits(SECTOR_OK, sector); return SAVE_STATUS_OK; } } -u8 TryReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunk) +static u8 TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk *chunks) { - u8 retVal; - gReadWriteSector = eSaveSection; - if (a1 != 0xFFFF) + u8 status; + gReadWriteSector = gSaveDataBuffer; + if (sectorId != FULL_SAVE_SLOT) { - retVal = SAVE_STATUS_ERROR; + // This function may not be used with a specific sector id + status = SAVE_STATUS_ERROR; } else { - retVal = GetSaveValidStatus(chunk); - ReadAllSaveSectorsCurrentSlot(0xFFFF, chunk); + status = GetSaveValidStatus(chunks); + CopySaveSlotData(FULL_SAVE_SLOT, chunks); } - return retVal; + return status; } -u8 ReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunks) +// sectorId arg is ignored, this always reads the full save slot +static u8 CopySaveSlotData(u16 sectorId, const struct SaveBlockChunk *chunks) { u16 i; u16 checksum; - u16 sector = NUM_SECTORS_PER_SLOT * (gSaveCounter % 2); + u16 slotOffset = NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS); u16 id; for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) { - DoReadFlashWholeSection(i + sector, gReadWriteSector); + ReadFlashSector(i + slotOffset, gReadWriteSector); + id = gReadWriteSector->id; if (id == 0) gLastWrittenSector = i; + checksum = CalculateChecksum(gReadWriteSector->data, chunks[id].size); - if (gReadWriteSector->security == SECTOR_SECURITY_NUM - && gReadWriteSector->checksum == checksum) + + // Only copy data for sectors whose security and checksum fields are correct + if (gReadWriteSector->security == SECTOR_SECURITY_NUM && gReadWriteSector->checksum == checksum) { u16 j; for (j = 0; j < chunks[id].size; j++) @@ -533,13 +566,13 @@ u8 ReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunks) } } - return 1; + return SAVE_STATUS_OK; } -u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) +static u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) { - u16 sector; - bool8 signatureValid; + u16 i; + bool8 securityPassed; u16 checksum; u32 slot1saveCounter = 0; u32 slot2saveCounter = 0; @@ -548,15 +581,15 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) u32 validSectors; const u32 ALL_SECTORS = (1 << NUM_SECTORS_PER_SLOT) - 1; // bitmask of all saveblock sectors - // check save slot 1. + // Check save slot 1 validSectors = 0; - signatureValid = FALSE; - for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++) + securityPassed = FALSE; + for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) { - DoReadFlashWholeSection(sector, gReadWriteSector); + ReadFlashSector(i, gReadWriteSector); if (gReadWriteSector->security == SECTOR_SECURITY_NUM) { - signatureValid = TRUE; + securityPassed = TRUE; checksum = CalculateChecksum(gReadWriteSector->data, chunks[gReadWriteSector->id].size); if (gReadWriteSector->checksum == checksum) { @@ -566,7 +599,7 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) } } - if (signatureValid) + if (securityPassed) { if (validSectors == ALL_SECTORS) slot1Status = SAVE_STATUS_OK; @@ -575,18 +608,19 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) } else { + // No sectors in slot 1 have the security number, treat it as empty slot1Status = SAVE_STATUS_EMPTY; } - // check save slot 2. + // Check save slot 2 validSectors = 0; - signatureValid = FALSE; - for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++) + securityPassed = FALSE; + for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) { - DoReadFlashWholeSection(NUM_SECTORS_PER_SLOT + sector, gReadWriteSector); + ReadFlashSector(NUM_SECTORS_PER_SLOT + i, gReadWriteSector); if (gReadWriteSector->security == SECTOR_SECURITY_NUM) { - signatureValid = TRUE; + securityPassed = TRUE; checksum = CalculateChecksum(gReadWriteSector->data, chunks[gReadWriteSector->id].size); if (gReadWriteSector->checksum == checksum) { @@ -596,7 +630,7 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) } } - if (signatureValid) + if (securityPassed) { if (validSectors == ALL_SECTORS) slot2Status = SAVE_STATUS_OK; @@ -605,13 +639,15 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) } else { + // No sectors in slot 2 have the security number, treat it as empty. slot2Status = SAVE_STATUS_EMPTY; } if (slot1Status == SAVE_STATUS_OK && slot2Status == SAVE_STATUS_OK) { // Choose counter of the most recent save file - if ((slot1saveCounter == -1 && slot2saveCounter == 0) || (slot1saveCounter == 0 && slot2saveCounter == -1)) + if ((slot1saveCounter == -1 && slot2saveCounter == 0) + || (slot1saveCounter == 0 && slot2saveCounter == -1)) { if ((unsigned)(slot1saveCounter + 1) < (unsigned)(slot2saveCounter + 1)) gSaveCounter = slot2saveCounter; @@ -628,69 +664,78 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks) return SAVE_STATUS_OK; } + // One or both save slots are not OK + if (slot1Status == SAVE_STATUS_OK) { gSaveCounter = slot1saveCounter; if (slot2Status == SAVE_STATUS_ERROR) - return SAVE_STATUS_ERROR; + return SAVE_STATUS_ERROR; // Slot 2 errored else - return SAVE_STATUS_OK; + return SAVE_STATUS_OK; // Slot 1 is OK, slot 2 is empty } if (slot2Status == SAVE_STATUS_OK) { gSaveCounter = slot2saveCounter; if (slot1Status == SAVE_STATUS_ERROR) - return SAVE_STATUS_ERROR; + return SAVE_STATUS_ERROR; // Slot 1 errored else - return SAVE_STATUS_OK; + return SAVE_STATUS_OK; // Slot 2 is OK, slot 1 is empty } - if (slot1Status == SAVE_STATUS_EMPTY && slot2Status == SAVE_STATUS_EMPTY) + // Neither slot is OK, check if both are empty + if (slot1Status == SAVE_STATUS_EMPTY + && slot2Status == SAVE_STATUS_EMPTY) { gSaveCounter = 0; gLastWrittenSector = 0; return SAVE_STATUS_EMPTY; } + // Both slots errored gSaveCounter = 0; gLastWrittenSector = 0; - return 2; + return SAVE_STATUS_CORRUPT; } -u8 ReadSomeUnknownSectorAndVerify(u8 sector, u8 *data, u16 size) +// Unused +static u8 TryLoadSaveSector(u8 sectorId, u8 *data, u16 size) { u16 i; - struct SaveSector *section = eSaveSection; - - DoReadFlashWholeSection(sector, section); - if (section->security == SECTOR_SECURITY_NUM) + struct SaveSector *sector = gSaveDataBuffer; + ReadFlashSector(sectorId, sector); + if (sector->security == SECTOR_SECURITY_NUM) { - u16 checksum = CalculateChecksum(section->data, size); - if (section->id == checksum) + u16 checksum = CalculateChecksum(sector->data, size); + if (sector->id == checksum) { + // Security and checksum are correct, copy data for (i = 0; i < size; i++) - data[i] = section->data[i]; + data[i] = sector->data[i]; return SAVE_STATUS_OK; } else { - return 2; + // Incorrect checksum + return SAVE_STATUS_CORRUPT; } } else { + // Incorrect security value return SAVE_STATUS_EMPTY; } } -u32 DoReadFlashWholeSection(u8 sector, struct SaveSector *section) +// Return value always ignored +static u32 ReadFlashSector(u8 sectorId, struct SaveSector *sector) { - ReadFlash(sector, 0, section->data, sizeof(struct SaveSector)); + ReadFlash(sectorId, 0, sector->data, SECTOR_SIZE); return 1; } -u16 CalculateChecksum(const void *data, u16 size) +static u16 CalculateChecksum(const void *data, u16 size) { u16 i; u32 checksum = 0; @@ -704,15 +749,18 @@ u16 CalculateChecksum(const void *data, u16 size) return ((checksum >> 16) + checksum); } -void nullsub_0201182C() +// Unused +static void SaveDummy1() { } -void nullsub_02011830() +// Unused +static void SaveDummy2() { } -void nullsub_02011834() +// Unused +static void SaveDummy3() { } @@ -745,7 +793,7 @@ bool32 flash_maincb_reset_pacifidlog_tm(void) if (gRtcUTCTime.days < 0) return FALSE; *GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1; - if (flash_write_save_block_chunks_check_damage(0) != TRUE) + if (BerryFix_TrySave(SAVE_NORMAL) != SAVE_STATUS_OK) return FALSE; return TRUE; -} +} \ No newline at end of file diff --git a/payload/sym_common.txt b/payload/sym_common.txt index 4087de6..8317f49 100644 --- a/payload/sym_common.txt +++ b/payload/sym_common.txt @@ -1,29 +1,4 @@ .include "main.o" .include "rtc.o" - - .align 4 -gLastWrittenSector: @ 0x03001220 - .space 0x4 - -gPrevSaveCounter: @ 0x03001224 - .space 0x4 - -gLastKnownGoodSector: @ 0x03001228 - .space 0x4 - -gDamagedSaveSectors: @ 0x0300122C - .space 0x4 - -gSaveCounter: @ 0x03001230 - .space 0x4 - -gReadWriteSector: @ 0x03001234 - .space 0x4 - -gCurSaveChunk: - .space 0x4 - -gFlashIdentIsValid: @ 0x0300123C - .space 0x4 - - .include "agb_flash.o" + .include "save.o" + .include "agb_flash.o" From 4a0b0f67eab12323d6ca35745636d6718f4dc523 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:38:19 -0500 Subject: [PATCH 05/12] Split berry_fix_save.c from save.c --- payload/include/berry_fix_save.h | 8 +++ payload/include/save.h | 21 ++++++-- payload/ld_script.txt | 1 + payload/src/berry_fix_save.c | 70 +++++++++++++++++++++++++++ payload/src/main.c | 1 + payload/src/save.c | 83 ++------------------------------ 6 files changed, 100 insertions(+), 84 deletions(-) create mode 100644 payload/include/berry_fix_save.h create mode 100644 payload/src/berry_fix_save.c diff --git a/payload/include/berry_fix_save.h b/payload/include/berry_fix_save.h new file mode 100644 index 0000000..b657619 --- /dev/null +++ b/payload/include/berry_fix_save.h @@ -0,0 +1,8 @@ +#ifndef GUARD_BERRY_FIX_SAVE_H +#define GUARD_BERRY_FIX_SAVE_H + +bool32 BerryFix_IdentifyFlash(void); +u8 BerryFix_TrySave(u8 mode); +bool8 BerryFix_LoadSave(u32); + +#endif //GUARD_BERRY_FIX_SAVE_H diff --git a/payload/include/save.h b/payload/include/save.h index da3ea2e..f1fe584 100644 --- a/payload/include/save.h +++ b/payload/include/save.h @@ -1,5 +1,5 @@ -#ifndef GUARD_FLASH_H -#define GUARD_FLASH_H +#ifndef GUARD_SAVE_H +#define GUARD_SAVE_H // Each 4 KiB flash sector contains 3968 bytes of actual data followed by a 128 byte footer. // Only 12 bytes of the footer are used. @@ -58,6 +58,12 @@ enum MsgBoxUpdateMessage MSGBOX_UPDATING }; +struct SaveBlockChunk +{ + u8 * data; + u16 size; +}; + struct SaveSector { u8 data[SECTOR_DATA_SIZE]; @@ -70,11 +76,16 @@ struct SaveSector #define SECTOR_SECURITY_OFFSET offsetof(struct SaveSector, security) -bool32 BerryFix_IdentifyFlash(void); -bool8 BerryFix_LoadSave(u32); +extern u32 gDamagedSaveSectors; +extern bool32 gFlashIdentIsValid; +extern const struct SaveBlockChunk gSaveBlockChunks[]; + +u8 WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk *chunks); +u8 TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk *chunks); + void msg_load_gfx(void); void msg_display(enum MsgBoxUpdateMessage); bool32 flash_maincb_check_need_reset_pacifidlog_tm(void); bool32 flash_maincb_reset_pacifidlog_tm(void); -#endif //GUARD_FLASH_H +#endif //GUARD_SAVE_H diff --git a/payload/ld_script.txt b/payload/ld_script.txt index 1f0c4c9..6996c2e 100644 --- a/payload/ld_script.txt +++ b/payload/ld_script.txt @@ -9,6 +9,7 @@ SECTIONS { asm/crt0.o(.text); src/main.o(.text); src/rtc.o(.text); + src/berry_fix_save.o(.text); src/save.o(.text); } =0 diff --git a/payload/src/berry_fix_save.c b/payload/src/berry_fix_save.c new file mode 100644 index 0000000..ff3fe5f --- /dev/null +++ b/payload/src/berry_fix_save.c @@ -0,0 +1,70 @@ +#include "global.h" +#include "main.h" +#include "save.h" + +bool32 BerryFix_IdentifyFlash(void) +{ + gFlashIdentIsValid = TRUE; + if (!IdentifyFlash()) + { + SetFlashTimerIntr(0, &((IntrFunc *)gIntrFuncPointers)[9]); + return TRUE; + } + gFlashIdentIsValid = FALSE; + return FALSE; +} + +// Unused +static void BerryFix_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size) +{ + ReadFlash(sectorNum, offset, dest, size); +} + +static u8 BerryFix_WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk * chunks) +{ + return WriteSaveSectorOrSlot(sectorId, chunks); +} + +static u8 BerryFix_TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk * chunks) +{ + return TryLoadSaveSlot(sectorId, chunks); +} + +static u32 * BerryFix_GetDamagedSaveSectors(void) +{ + return &gDamagedSaveSectors; +} + +static s32 BerryFix_Save(u8 mode) +{ + u8 i; + switch (mode) + { + case SAVE_NORMAL: + default: + BerryFix_WriteSaveSectorOrSlot(FULL_SAVE_SLOT, gSaveBlockChunks); + break; + case SAVE_SAVEBLOCKS: + for (i = SECTOR_ID_SAVEBLOCK2; i <= SECTOR_ID_SAVEBLOCK1_END; i++) + BerryFix_WriteSaveSectorOrSlot(i, gSaveBlockChunks); + break; + case SAVE_SAVEBLOCK2: + BerryFix_WriteSaveSectorOrSlot(SECTOR_ID_SAVEBLOCK2, gSaveBlockChunks); + break; + } + + return 0; +} + +u8 BerryFix_TrySave(u8 mode) +{ + BerryFix_Save(mode); + if (*BerryFix_GetDamagedSaveSectors() == 0) + return SAVE_STATUS_OK; + return SAVE_STATUS_ERROR; +} + +u8 BerryFix_LoadSave(u32 unused) +{ + return BerryFix_TryLoadSaveSlot(FULL_SAVE_SLOT, gSaveBlockChunks); +} diff --git a/payload/src/main.c b/payload/src/main.c index e00db91..3ffff8a 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -2,6 +2,7 @@ #include "global.h" #include "main.h" #include "rtc.h" +#include "berry_fix_save.h" #include "save.h" static s32 gInitialWaitTimer; diff --git a/payload/src/save.c b/payload/src/save.c index d65d509..b096966 100644 --- a/payload/src/save.c +++ b/payload/src/save.c @@ -1,5 +1,4 @@ #include "global.h" -#include "main.h" #include "save.h" #include "rtc.h" @@ -8,17 +7,9 @@ Much of it lies unused. */ -struct SaveBlockChunk -{ - u8 * data; - u16 size; -}; - -static u8 WriteSaveSectorOrSlot(u16, const struct SaveBlockChunk *); static u8 HandleWriteSector(u16, const struct SaveBlockChunk *); static u8 TryWriteSector(u8, u8 *); static u8 HandleReplaceSector(u16, const struct SaveBlockChunk *); -static u8 TryLoadSaveSlot(u16, const struct SaveBlockChunk *); static u8 CopySaveSlotData(u16, const struct SaveBlockChunk *); static u8 GetSaveValidStatus(const struct SaveBlockChunk *); static u32 ReadFlashSector(u8, struct SaveSector *); @@ -45,7 +36,7 @@ EWRAM_DATA struct PokemonStorage gPokemonStorage = {}; min(sizeof(structure) - chunkNum * SECTOR_DATA_SIZE, SECTOR_DATA_SIZE) \ } \ -static const struct SaveBlockChunk sSaveBlockChunks[] = +const struct SaveBlockChunk gSaveBlockChunks[] = { SAVEBLOCK_CHUNK(gSaveBlock2, 0), @@ -69,73 +60,6 @@ const u16 gInfoMessagesPal[] = INCBIN_U16("graphics/msg_box.gbapal"); const u8 gInfoMessagesTilemap[] = INCBIN_U8("graphics/msg_box.tilemap.lz"); const u8 gInfoMessagesGfx[] = INCBIN_U8("graphics/msg_box.4bpp.lz"); -bool32 BerryFix_IdentifyFlash(void) -{ - gFlashIdentIsValid = TRUE; - if (!IdentifyFlash()) - { - SetFlashTimerIntr(0, &((IntrFunc *)gIntrFuncPointers)[9]); - return TRUE; - } - gFlashIdentIsValid = FALSE; - return FALSE; -} - -// Unused -static void BerryFix_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size) -{ - ReadFlash(sectorNum, offset, dest, size); -} - -static u8 BerryFix_WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk * chunks) -{ - return WriteSaveSectorOrSlot(sectorId, chunks); -} - -static u8 BerryFix_TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk * chunks) -{ - return TryLoadSaveSlot(sectorId, chunks); -} - -static u32 * BerryFix_GetDamagedSaveSectors(void) -{ - return &gDamagedSaveSectors; -} - -static s32 BerryFix_Save(u8 mode) -{ - u8 i; - switch (mode) - { - case SAVE_NORMAL: - default: - BerryFix_WriteSaveSectorOrSlot(FULL_SAVE_SLOT, sSaveBlockChunks); - break; - case SAVE_SAVEBLOCKS: - for (i = SECTOR_ID_SAVEBLOCK2; i <= SECTOR_ID_SAVEBLOCK1_END; i++) - BerryFix_WriteSaveSectorOrSlot(i, sSaveBlockChunks); - break; - case SAVE_SAVEBLOCK2: - BerryFix_WriteSaveSectorOrSlot(SECTOR_ID_SAVEBLOCK2, sSaveBlockChunks); - break; - } - - return 0; -} - -u8 BerryFix_TrySave(u8 mode) -{ - BerryFix_Save(mode); - if (*BerryFix_GetDamagedSaveSectors() == 0) - return SAVE_STATUS_OK; - return SAVE_STATUS_ERROR; -} - -u8 BerryFix_LoadSave(u32 unused) -{ - return BerryFix_TryLoadSaveSlot(FULL_SAVE_SLOT, sSaveBlockChunks); -} - void msg_load_gfx(void) { REG_DISPCNT = 0; @@ -213,7 +137,7 @@ static bool32 SetDamagedSectorBits(u8 op, u8 sectorId) return retVal; } -static u8 WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk *chunks) +u8 WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk *chunks) { u32 status; u16 i; @@ -521,7 +445,7 @@ static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *chu } } -static u8 TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk *chunks) +u8 TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk *chunks) { u8 status; gReadWriteSector = gSaveDataBuffer; @@ -784,6 +708,7 @@ bool32 flash_maincb_check_need_reset_pacifidlog_tm(void) return FALSE; } +extern u8 BerryFix_TrySave(u8 mode); bool32 flash_maincb_reset_pacifidlog_tm(void) { u8 sp0; From 4c04e13962e5753736ea7de1eca1ec3296b362eb Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:44:30 -0500 Subject: [PATCH 06/12] Split event_data.c from save.c --- payload/include/berry_fix_save.h | 9 ++++++ payload/include/event_data.h | 7 +++++ payload/include/save.h | 7 ----- payload/ld_script.txt | 1 + payload/src/berry_fix_save.c | 2 +- payload/src/event_data.c | 53 ++++++++++++++++++++++++++++++++ payload/src/main.c | 6 ++-- payload/src/rtc.c | 4 +-- payload/src/save.c | 50 ------------------------------ 9 files changed, 76 insertions(+), 63 deletions(-) create mode 100644 payload/include/event_data.h create mode 100644 payload/src/event_data.c diff --git a/payload/include/berry_fix_save.h b/payload/include/berry_fix_save.h index b657619..7a2d75b 100644 --- a/payload/include/berry_fix_save.h +++ b/payload/include/berry_fix_save.h @@ -1,6 +1,15 @@ #ifndef GUARD_BERRY_FIX_SAVE_H #define GUARD_BERRY_FIX_SAVE_H +#include "save.h" + +enum +{ + SAVE_NORMAL, // Save full save slot + SAVE_SAVEBLOCKS, // Save just SaveBlock1 and SaveBlock2 + SAVE_SAVEBLOCK2, // Save just SaveBlock2 +}; + bool32 BerryFix_IdentifyFlash(void); u8 BerryFix_TrySave(u8 mode); bool8 BerryFix_LoadSave(u32); diff --git a/payload/include/event_data.h b/payload/include/event_data.h new file mode 100644 index 0000000..db83834 --- /dev/null +++ b/payload/include/event_data.h @@ -0,0 +1,7 @@ +#ifndef GUARD_EVENT_DATA_H +#define GUARD_EVENT_DATA_H + +bool32 BerryFix_ShouldResetPacifidlogTM(void); +bool32 BerryFix_ResetPacifidlogTM(void); + +#endif //GUARD_EVENT_DATA_H diff --git a/payload/include/save.h b/payload/include/save.h index f1fe584..2e731ce 100644 --- a/payload/include/save.h +++ b/payload/include/save.h @@ -42,13 +42,6 @@ enum SECTOR_CHECK, // unused }; -enum -{ - SAVE_NORMAL, // Save full save slot - SAVE_SAVEBLOCKS, // Save just SaveBlock1 and SaveBlock2 - SAVE_SAVEBLOCK2, // Save just SaveBlock2 -}; - enum MsgBoxUpdateMessage { MSGBOX_WILL_NOW_UPDATE = 0, diff --git a/payload/ld_script.txt b/payload/ld_script.txt index 6996c2e..7b3ed26 100644 --- a/payload/ld_script.txt +++ b/payload/ld_script.txt @@ -11,6 +11,7 @@ SECTIONS { src/rtc.o(.text); src/berry_fix_save.o(.text); src/save.o(.text); + src/event_data.o(.text); } =0 lib_text : diff --git a/payload/src/berry_fix_save.c b/payload/src/berry_fix_save.c index ff3fe5f..6f2ba38 100644 --- a/payload/src/berry_fix_save.c +++ b/payload/src/berry_fix_save.c @@ -1,6 +1,6 @@ #include "global.h" #include "main.h" -#include "save.h" +#include "berry_fix_save.h" bool32 BerryFix_IdentifyFlash(void) { diff --git a/payload/src/event_data.c b/payload/src/event_data.c new file mode 100644 index 0000000..f7162a3 --- /dev/null +++ b/payload/src/event_data.c @@ -0,0 +1,53 @@ +#include "global.h" +#include "rtc.h" +#include "berry_fix_save.h" +#include "event_data.h" + +// Unused +static void Dummy1() +{ +} + +// Unused +static void Dummy2() +{ +} + +// Unused +static void Dummy3() +{ +} + +static u16 * GetVarPointer(u16 id) +{ + if (id < VARS_START) + return NULL; + if (id < SPECIAL_VARS_START) + return &gSaveBlock1.vars[id - VARS_START]; + return NULL; +} + +bool32 BerryFix_ShouldResetPacifidlogTM(void) +{ + u8 year; + u16 * var = GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY); + rtc_maincb_is_time_since_last_berry_update_positive(&year); + if (*var <= gRtcUTCTime.days) + return TRUE; + else + return FALSE; +} + +bool32 BerryFix_ResetPacifidlogTM(void) +{ + u8 year; + if (BerryFix_ShouldResetPacifidlogTM() == TRUE) + return TRUE; + rtc_maincb_is_time_since_last_berry_update_positive(&year); + if (gRtcUTCTime.days < 0) + return FALSE; + *GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1; + if (BerryFix_TrySave(SAVE_NORMAL) != SAVE_STATUS_OK) + return FALSE; + return TRUE; +} diff --git a/payload/src/main.c b/payload/src/main.c index 3ffff8a..3891502 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -3,7 +3,7 @@ #include "main.h" #include "rtc.h" #include "berry_fix_save.h" -#include "save.h" +#include "event_data.h" static s32 gInitialWaitTimer; IntrFunc gIntrTable[16]; @@ -234,14 +234,14 @@ void main_callback(u32 * state, void * unused1, void * unused2) *state = MAINCB_CHECK_PACIFIDLOG_TM; break; case MAINCB_CHECK_PACIFIDLOG_TM: - if (flash_maincb_check_need_reset_pacifidlog_tm() == TRUE) + if (BerryFix_ShouldResetPacifidlogTM() == TRUE) *state = MAINCB_FINISHED; else *state = MAINCB_FIX_PACIFIDLOG_TM; break; case MAINCB_FIX_PACIFIDLOG_TM: msg_display(MSGBOX_UPDATING); - if (flash_maincb_reset_pacifidlog_tm() == TRUE) + if (BerryFix_ResetPacifidlogTM() == TRUE) { gUpdateSuccessful |= 1; *state = MAINCB_FINISHED; diff --git a/payload/src/rtc.c b/payload/src/rtc.c index e73f522..43980b7 100644 --- a/payload/src/rtc.c +++ b/payload/src/rtc.c @@ -251,10 +251,10 @@ void rtc_set_datetime(struct SiiRtcInfo * info) REG_IME = imeBak; } -bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 * a0) +bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 * year) { rtc_get_status_and_datetime(&sRtcInfoWork); - *a0 = bcd_to_hex(sRtcInfoWork.year); + *year = bcd_to_hex(sRtcInfoWork.year); rtc_sub_time_from_datetime(&sRtcInfoWork, &gRtcUTCTime, LocalTimeOffset); rtc_sub_time_from_time(&gTimeSinceBerryUpdate, LastBerryTreeUpdate, &gRtcUTCTime); if (gTimeSinceBerryUpdate.days * 1440 + gTimeSinceBerryUpdate.hours * 60 + gTimeSinceBerryUpdate.minutes >= 0) diff --git a/payload/src/save.c b/payload/src/save.c index b096966..40fd33b 100644 --- a/payload/src/save.c +++ b/payload/src/save.c @@ -672,53 +672,3 @@ static u16 CalculateChecksum(const void *data, u16 size) return ((checksum >> 16) + checksum); } - -// Unused -static void SaveDummy1() -{ -} - -// Unused -static void SaveDummy2() -{ -} - -// Unused -static void SaveDummy3() -{ -} - -static u16 * GetVarPointer(u16 id) -{ - if (id < VARS_START) - return NULL; - if (id < SPECIAL_VARS_START) - return &gSaveBlock1.vars[id - VARS_START]; - return NULL; -} - -bool32 flash_maincb_check_need_reset_pacifidlog_tm(void) -{ - u8 sp0; - u16 * data = GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY); - rtc_maincb_is_time_since_last_berry_update_positive(&sp0); - if (*data <= gRtcUTCTime.days) - return TRUE; - else - return FALSE; -} - -extern u8 BerryFix_TrySave(u8 mode); -bool32 flash_maincb_reset_pacifidlog_tm(void) -{ - u8 sp0; - if (flash_maincb_check_need_reset_pacifidlog_tm() == TRUE) - return TRUE; - rtc_maincb_is_time_since_last_berry_update_positive(&sp0); - if (gRtcUTCTime.days < 0) - return FALSE; - *GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1; - if (BerryFix_TrySave(SAVE_NORMAL) != SAVE_STATUS_OK) - return FALSE; - return TRUE; -} \ No newline at end of file From 4a96086ff1bbbce70c062ec1adbf1af65e2a248b Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:51:32 -0500 Subject: [PATCH 07/12] Split message_box.c from save.c --- .../{msg_box.tilemap => messages.bin} | Bin .../graphics/{msg_box.png => messages.png} | Bin payload/include/message_box.h | 16 ++++++ payload/include/save.h | 21 -------- payload/ld_script.txt | 2 + payload/src/main.c | 15 +++--- payload/src/message_box.c | 46 ++++++++++++++++++ payload/src/save.c | 45 ----------------- 8 files changed, 72 insertions(+), 73 deletions(-) rename payload/graphics/{msg_box.tilemap => messages.bin} (100%) rename payload/graphics/{msg_box.png => messages.png} (100%) create mode 100644 payload/include/message_box.h create mode 100644 payload/src/message_box.c diff --git a/payload/graphics/msg_box.tilemap b/payload/graphics/messages.bin similarity index 100% rename from payload/graphics/msg_box.tilemap rename to payload/graphics/messages.bin diff --git a/payload/graphics/msg_box.png b/payload/graphics/messages.png similarity index 100% rename from payload/graphics/msg_box.png rename to payload/graphics/messages.png diff --git a/payload/include/message_box.h b/payload/include/message_box.h new file mode 100644 index 0000000..ecff960 --- /dev/null +++ b/payload/include/message_box.h @@ -0,0 +1,16 @@ +#ifndef GUARD_MESSAGE_BOX_H +#define GUARD_MESSAGE_BOX_H + +enum Message +{ + MSG_WILL_NOW_UPDATE = 0, + MSG_HAS_BEEN_UPDATED, + MSG_UNABLE_TO_UPDATE, + MSG_NO_NEED_TO_UPDATE, + MSG_UPDATING +}; + +void MessageBox_Load(void); +void MessageBox_Display(enum Message); + +#endif //GUARD_MESSAGE_BOX_H diff --git a/payload/include/save.h b/payload/include/save.h index 2e731ce..3dfb44a 100644 --- a/payload/include/save.h +++ b/payload/include/save.h @@ -15,14 +15,7 @@ #define SECTOR_ID_SAVEBLOCK2 0 #define SECTOR_ID_SAVEBLOCK1_START 1 #define SECTOR_ID_SAVEBLOCK1_END 4 -#define SECTOR_ID_PKMN_STORAGE_START 5 -#define SECTOR_ID_PKMN_STORAGE_END 13 #define NUM_SECTORS_PER_SLOT 14 -// Save Slot 1: 0-13; Save Slot 2: 14-27 -#define SECTOR_ID_HOF_1 28 -#define SECTOR_ID_HOF_2 29 -#define SECTOR_ID_TRAINER_HILL 30 -#define SECTOR_ID_RECORDED_BATTLE 31 #define SECTORS_COUNT 32 #define SAVE_STATUS_EMPTY 0 @@ -42,15 +35,6 @@ enum SECTOR_CHECK, // unused }; -enum MsgBoxUpdateMessage -{ - MSGBOX_WILL_NOW_UPDATE = 0, - MSGBOX_HAS_BEEN_UPDATED, - MSGBOX_UNABLE_TO_UPDATE, - MSGBOX_NO_NEED_TO_UPDATE, - MSGBOX_UPDATING -}; - struct SaveBlockChunk { u8 * data; @@ -76,9 +60,4 @@ extern const struct SaveBlockChunk gSaveBlockChunks[]; u8 WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk *chunks); u8 TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk *chunks); -void msg_load_gfx(void); -void msg_display(enum MsgBoxUpdateMessage); -bool32 flash_maincb_check_need_reset_pacifidlog_tm(void); -bool32 flash_maincb_reset_pacifidlog_tm(void); - #endif //GUARD_SAVE_H diff --git a/payload/ld_script.txt b/payload/ld_script.txt index 7b3ed26..9b349aa 100644 --- a/payload/ld_script.txt +++ b/payload/ld_script.txt @@ -10,6 +10,7 @@ SECTIONS { src/main.o(.text); src/rtc.o(.text); src/berry_fix_save.o(.text); + src/message_box.o(.text); src/save.o(.text); src/event_data.o(.text); } =0 @@ -34,6 +35,7 @@ SECTIONS { src/main.o(.rodata); src/rtc.o(.rodata); src/save.o(.rodata); + src/message_box.o(.rodata); } =0 lib_rodata : diff --git a/payload/src/main.c b/payload/src/main.c index 3891502..bb78e7d 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -4,6 +4,7 @@ #include "rtc.h" #include "berry_fix_save.h" #include "event_data.h" +#include "message_box.h" static s32 gInitialWaitTimer; IntrFunc gIntrTable[16]; @@ -70,7 +71,7 @@ void AgbMain(void) REG_IE |= INTR_FLAG_GAMEPAK; REG_DISPSTAT = DISPSTAT_VBLANK_INTR; REG_IME = INTR_FLAG_VBLANK; - msg_load_gfx(); + MessageBox_Load(); gMainCallbackState = MAINCB_INIT; gUnknown_3001194 = 0; for (;;) @@ -173,7 +174,7 @@ void main_callback(u32 * state, void * unused1, void * unused2) switch (*state) { case MAINCB_INIT: - msg_display(MSGBOX_WILL_NOW_UPDATE); + MessageBox_Display(MSG_WILL_NOW_UPDATE); if (++gInitialWaitTimer >= 180) { gInitialWaitTimer = 0; @@ -240,7 +241,7 @@ void main_callback(u32 * state, void * unused1, void * unused2) *state = MAINCB_FIX_PACIFIDLOG_TM; break; case MAINCB_FIX_PACIFIDLOG_TM: - msg_display(MSGBOX_UPDATING); + MessageBox_Display(MSG_UPDATING); if (BerryFix_ResetPacifidlogTM() == TRUE) { gUpdateSuccessful |= 1; @@ -253,16 +254,16 @@ void main_callback(u32 * state, void * unused1, void * unused2) if (gUpdateSuccessful == 0) *state = MAINCB_NO_NEED_TO_FIX; else - msg_display(MSGBOX_HAS_BEEN_UPDATED); + MessageBox_Display(MSG_HAS_BEEN_UPDATED); break; case MAINCB_NO_NEED_TO_FIX: - msg_display(MSGBOX_NO_NEED_TO_UPDATE); + MessageBox_Display(MSG_NO_NEED_TO_UPDATE); break; case MAINCB_YEAR_MAKES_NO_SENSE: - msg_display(MSGBOX_UNABLE_TO_UPDATE); + MessageBox_Display(MSG_UNABLE_TO_UPDATE); break; case MAINCB_ERROR: - msg_display(MSGBOX_UNABLE_TO_UPDATE); + MessageBox_Display(MSG_UNABLE_TO_UPDATE); break; } } diff --git a/payload/src/message_box.c b/payload/src/message_box.c new file mode 100644 index 0000000..b66b2d8 --- /dev/null +++ b/payload/src/message_box.c @@ -0,0 +1,46 @@ +#include "global.h" +#include "message_box.h" + +static const u16 sMessages_Pal[] = INCBIN_U16("graphics/messages.gbapal"); +static const u8 sMessages_Tilemap[] = INCBIN_U8("graphics/messages.bin.lz"); +static const u8 sMessages_Gfx[] = INCBIN_U8("graphics/messages.4bpp.lz"); + +void MessageBox_Load(void) +{ + REG_DISPCNT = 0; + REG_BG0HOFS = 0; + REG_BG0VOFS = 0; + REG_BLDCNT = 0; + LZ77UnCompVram(sMessages_Gfx, (void *)BG_VRAM); + LZ77UnCompVram(sMessages_Tilemap, (void *)BG_SCREEN_ADDR(28)); + CpuCopy16(sMessages_Pal, (void *)BG_PLTT, BG_PLTT_SIZE); + REG_BG0CNT = BGCNT_SCREENBASE(28) | BGCNT_TXT512x512; + REG_DISPCNT = DISPCNT_BG0_ON; +} + +void MessageBox_Display(enum Message msg) +{ + switch (msg) + { + case MSG_WILL_NOW_UPDATE: + REG_BG0HOFS = 0; + REG_BG0VOFS = 0; + break; + case MSG_HAS_BEEN_UPDATED: + REG_BG0HOFS = 0x100; + REG_BG0VOFS = 0; + break; + case MSG_UNABLE_TO_UPDATE: + REG_BG0HOFS = 0x100; + REG_BG0VOFS = 0xB0; + break; + case MSG_NO_NEED_TO_UPDATE: + REG_BG0HOFS = 0; + REG_BG0VOFS = 0xB0; + break; + case MSG_UPDATING: + REG_BG0HOFS = 0; + REG_BG0VOFS = 0x160; + break; + } +} diff --git a/payload/src/save.c b/payload/src/save.c index 40fd33b..37ef8e5 100644 --- a/payload/src/save.c +++ b/payload/src/save.c @@ -1,6 +1,5 @@ #include "global.h" #include "save.h" -#include "rtc.h" /* The Berry Fix Program contains a copy of most of Ruby/Sapphire's save code. @@ -56,50 +55,6 @@ const struct SaveBlockChunk gSaveBlockChunks[] = SAVEBLOCK_CHUNK(gPokemonStorage, 8), }; -const u16 gInfoMessagesPal[] = INCBIN_U16("graphics/msg_box.gbapal"); -const u8 gInfoMessagesTilemap[] = INCBIN_U8("graphics/msg_box.tilemap.lz"); -const u8 gInfoMessagesGfx[] = INCBIN_U8("graphics/msg_box.4bpp.lz"); - -void msg_load_gfx(void) -{ - REG_DISPCNT = 0; - REG_BG0HOFS = 0; - REG_BG0VOFS = 0; - REG_BLDCNT = 0; - LZ77UnCompVram(gInfoMessagesGfx, (void *)BG_VRAM); - LZ77UnCompVram(gInfoMessagesTilemap, (void *)BG_SCREEN_ADDR(28)); - CpuCopy16(gInfoMessagesPal, (void *)BG_PLTT, BG_PLTT_SIZE); - REG_BG0CNT = BGCNT_SCREENBASE(28) | BGCNT_TXT512x512; - REG_DISPCNT = DISPCNT_BG0_ON; -} - -void msg_display(enum MsgBoxUpdateMessage a0) -{ - switch (a0) - { - case MSGBOX_WILL_NOW_UPDATE: - REG_BG0HOFS = 0; - REG_BG0VOFS = 0; - break; - case MSGBOX_HAS_BEEN_UPDATED: - REG_BG0HOFS = 0x100; - REG_BG0VOFS = 0; - break; - case MSGBOX_UNABLE_TO_UPDATE: - REG_BG0HOFS = 0x100; - REG_BG0VOFS = 0xB0; - break; - case MSGBOX_NO_NEED_TO_UPDATE: - REG_BG0HOFS = 0; - REG_BG0VOFS = 0xB0; - break; - case MSGBOX_UPDATING: - REG_BG0HOFS = 0; - REG_BG0VOFS = 0x160; - break; - } -} - // Unused static void ClearSaveData(void) { From d74428a5d7f5ed2cf9fe80353eee524dfff39144 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:52:25 -0500 Subject: [PATCH 08/12] Sync siirtc --- payload/src/siirtc.c | 164 +++++++++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 69 deletions(-) diff --git a/payload/src/siirtc.c b/payload/src/siirtc.c index 965a068..5b05d99 100644 --- a/payload/src/siirtc.c +++ b/payload/src/siirtc.c @@ -46,6 +46,19 @@ #define CMD_TIME CMD(3) #define CMD_ALARM CMD(4) +#define SCK_HI 1 +#define SIO_HI 2 +#define CS_HI 4 + +#define DIR_0_IN 0 +#define DIR_0_OUT 1 +#define DIR_1_IN 0 +#define DIR_1_OUT 2 +#define DIR_2_IN 0 +#define DIR_2_OUT 4 +#define DIR_ALL_IN (DIR_0_IN | DIR_1_IN | DIR_2_IN) +#define DIR_ALL_OUT (DIR_0_OUT | DIR_1_OUT | DIR_2_OUT) + #define GPIO_PORT_DATA (*(vu16 *)0x80000C4) #define GPIO_PORT_DIRECTION (*(vu16 *)0x80000C6) #define GPIO_PORT_READ_ENABLE (*(vu16 *)0x80000C8) @@ -58,24 +71,25 @@ static bool8 sLocked; static int WriteCommand(u8 value); static int WriteData(u8 value); static u8 ReadData(); + static void EnableGpioPortRead(); static void DisableGpioPortRead(); static const char AgbLibRtcVersion[] = "SIIRTC_V001"; -void SiiRtcUnprotect() +void SiiRtcUnprotect(void) { EnableGpioPortRead(); sLocked = FALSE; } -void SiiRtcProtect() +void SiiRtcProtect(void) { DisableGpioPortRead(); sLocked = TRUE; } -u8 SiiRtcProbe() +u8 SiiRtcProbe(void) { u8 errorCode; struct SiiRtcInfo rtc; @@ -116,9 +130,9 @@ u8 SiiRtcProbe() return (errorCode << 4) | 1; } -bool8 SiiRtcReset() +bool8 SiiRtcReset(void) { - u8 result; + bool8 result; struct SiiRtcInfo rtc; if (sLocked == TRUE) @@ -126,15 +140,15 @@ bool8 SiiRtcReset() sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_RESET | WR); - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -154,14 +168,14 @@ bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc) sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_STATUS | RD); - GPIO_PORT_DIRECTION = 5; + GPIO_PORT_DIRECTION = DIR_0_OUT | DIR_1_IN | DIR_2_OUT; statusData = ReadData(); @@ -170,8 +184,8 @@ bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc) | ((statusData & STATUS_INTME) >> 2) | ((statusData & STATUS_INTFE) >> 1); - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -187,22 +201,22 @@ bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc) sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; statusData = STATUS_24HOUR | ((rtc->status & SIIRTCINFO_INTAE) << 3) | ((rtc->status & SIIRTCINFO_INTME) << 2) | ((rtc->status & SIIRTCINFO_INTFE) << 1); - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_STATUS | WR); WriteData(statusData); - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -218,22 +232,22 @@ bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc) sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_DATETIME | RD); - GPIO_PORT_DIRECTION = 5; + GPIO_PORT_DIRECTION = DIR_0_OUT | DIR_1_IN | DIR_2_OUT; for (i = 0; i < DATETIME_BUF_LEN; i++) DATETIME_BUF(rtc, i) = ReadData(); INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -249,18 +263,18 @@ bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc) sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_DATETIME | WR); for (i = 0; i < DATETIME_BUF_LEN; i++) WriteData(DATETIME_BUF(rtc, i)); - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -276,22 +290,22 @@ bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc) sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_TIME | RD); - GPIO_PORT_DIRECTION = 5; + GPIO_PORT_DIRECTION = DIR_0_OUT | DIR_1_IN | DIR_2_OUT; for (i = 0; i < TIME_BUF_LEN; i++) TIME_BUF(rtc, i) = ReadData(); INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -307,18 +321,18 @@ bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc) sLocked = TRUE; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIO_PORT_DIRECTION = 7; + GPIO_PORT_DIRECTION = DIR_ALL_OUT; WriteCommand(CMD_TIME | WR); for (i = 0; i < TIME_BUF_LEN; i++) WriteData(TIME_BUF(rtc, i)); - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -347,18 +361,18 @@ bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc) alarmData[1] = rtc->alarmMinute; - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - GPIOPortDirection = 7; // Why is this the only instance that uses a symbol? + GPIOPortDirection = DIR_ALL_OUT; // Why is this the only instance that uses a symbol? WriteCommand(CMD_ALARM | WR); for (i = 0; i < 2; i++) WriteData(alarmData[i]); - GPIO_PORT_DATA = 1; - GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = SCK_HI; + GPIO_PORT_DATA = SCK_HI; sLocked = FALSE; @@ -373,13 +387,17 @@ static int WriteCommand(u8 value) for (i = 0; i < 8; i++) { temp = ((value >> (7 - i)) & 1); - GPIO_PORT_DATA = (temp << 1) | 4; - GPIO_PORT_DATA = (temp << 1) | 4; - GPIO_PORT_DATA = (temp << 1) | 4; - GPIO_PORT_DATA = (temp << 1) | 5; + GPIO_PORT_DATA = (temp << 1) | CS_HI; + GPIO_PORT_DATA = (temp << 1) | CS_HI; + GPIO_PORT_DATA = (temp << 1) | CS_HI; + GPIO_PORT_DATA = (temp << 1) | SCK_HI | CS_HI; } - // control reaches end of non-void function + // Nothing uses the returned value from this function, + // so the undefined behavior is harmless in the vanilla game. +#ifdef UBFIX + return 0; +#endif } static int WriteData(u8 value) @@ -390,13 +408,17 @@ static int WriteData(u8 value) for (i = 0; i < 8; i++) { temp = ((value >> i) & 1); - GPIO_PORT_DATA = (temp << 1) | 4; - GPIO_PORT_DATA = (temp << 1) | 4; - GPIO_PORT_DATA = (temp << 1) | 4; - GPIO_PORT_DATA = (temp << 1) | 5; + GPIO_PORT_DATA = (temp << 1) | CS_HI; + GPIO_PORT_DATA = (temp << 1) | CS_HI; + GPIO_PORT_DATA = (temp << 1) | CS_HI; + GPIO_PORT_DATA = (temp << 1) | SCK_HI | CS_HI; } - // control reaches end of non-void function + // Nothing uses the returned value from this function, + // so the undefined behavior is harmless in the vanilla game. +#ifdef UBFIX + return 0; +#endif } static u8 ReadData() @@ -405,17 +427,21 @@ static u8 ReadData() u8 temp; u8 value; +#ifdef UBFIX + value = 0; +#endif + for (i = 0; i < 8; i++) { - GPIO_PORT_DATA = 4; - GPIO_PORT_DATA = 4; - GPIO_PORT_DATA = 4; - GPIO_PORT_DATA = 4; - GPIO_PORT_DATA = 4; - GPIO_PORT_DATA = 5; + GPIO_PORT_DATA = CS_HI; + GPIO_PORT_DATA = CS_HI; + GPIO_PORT_DATA = CS_HI; + GPIO_PORT_DATA = CS_HI; + GPIO_PORT_DATA = CS_HI; + GPIO_PORT_DATA = SCK_HI | CS_HI; - temp = ((GPIO_PORT_DATA & 2) >> 1); - value = (value >> 1) | (temp << 7); // UB: accessing uninitialized var + temp = ((GPIO_PORT_DATA & SIO_HI) >> 1); + value = (value >> 1) | (temp << 7); } return value; @@ -423,10 +449,10 @@ static u8 ReadData() static void EnableGpioPortRead() { - GPIO_PORT_READ_ENABLE = 1; + GPIO_PORT_READ_ENABLE = TRUE; } static void DisableGpioPortRead() { - GPIO_PORT_READ_ENABLE = 0; -} + GPIO_PORT_READ_ENABLE = FALSE; +} \ No newline at end of file From cb5ff5848b36956ccf18e61c453130619cef98b5 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:54:59 -0500 Subject: [PATCH 09/12] Sync rtc --- payload/include/rtc.h | 16 +- payload/include/siirtc.h | 6 +- payload/src/rtc.c | 373 +++++++++++++++++++++------------------ 3 files changed, 214 insertions(+), 181 deletions(-) diff --git a/payload/include/rtc.h b/payload/include/rtc.h index 35654d8..2ac6960 100644 --- a/payload/include/rtc.h +++ b/payload/include/rtc.h @@ -1,9 +1,19 @@ #ifndef GUARD_RTC_H #define GUARD_RTC_H -#include "gba/gba.h" -#include "siirtc.h" -#include "global.h" +#define RTC_INIT_ERROR 0x0001 +#define RTC_INIT_WARNING 0x0002 + +#define RTC_ERR_12HOUR_CLOCK 0x0010 +#define RTC_ERR_POWER_FAILURE 0x0020 +#define RTC_ERR_INVALID_YEAR 0x0040 +#define RTC_ERR_INVALID_MONTH 0x0080 +#define RTC_ERR_INVALID_DAY 0x0100 +#define RTC_ERR_INVALID_HOUR 0x0200 +#define RTC_ERR_INVALID_MINUTE 0x0400 +#define RTC_ERR_INVALID_SECOND 0x0800 + +#define RTC_ERR_FLAG_MASK 0x0FF0 extern struct Time gTimeSinceBerryUpdate; extern struct Time gRtcUTCTime; diff --git a/payload/include/siirtc.h b/payload/include/siirtc.h index de4fd63..12570e1 100644 --- a/payload/include/siirtc.h +++ b/payload/include/siirtc.h @@ -1,5 +1,5 @@ -#ifndef GUARD_RTC_H -#define GUARD_RTC_H +#ifndef GUARD_SIIRTC_H +#define GUARD_SIIRTC_H #include "gba/gba.h" @@ -51,4 +51,4 @@ bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc); bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc); bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc); -#endif // GUARD_RTC_H +#endif // GUARD_SIIRTC_H diff --git a/payload/src/rtc.c b/payload/src/rtc.c index 43980b7..a4f2fd8 100644 --- a/payload/src/rtc.c +++ b/payload/src/rtc.c @@ -1,286 +1,309 @@ -#include "gba/gba.h" -#include "siirtc.h" #include "global.h" +#include "siirtc.h" #include "main.h" +#include "rtc.h" struct Time gTimeSinceBerryUpdate; struct Time gRtcUTCTime; -static u16 sRtcProbeStatus; +static u16 sErrorStatus; static struct SiiRtcInfo sRtcInfoBuffer; -static u8 sRtcProbeCode; -static u16 sImeBak; +static u8 sProbeResult; +static u16 sSavedIme; static struct SiiRtcInfo sRtcInfoWork; -const struct SiiRtcInfo sDefaultRTC = { - .year = 0, // 2000 - .month = 1, // January - .day = 1, // 01 - .dayOfWeek = 0, - .hour = 0, - .minute = 0, - .second = 0, - .status = 0, - .alarmHour = 0, - .alarmMinute = 0 -}; -const s32 sDaysPerMonth[] = { - 31, - 28, - 31, - 30, - 31, - 30, - 31, - 31, - 30, - 31, - 30, - 31 +static const struct SiiRtcInfo sDefaultRTC = {0, MONTH_JAN, 1}; // 2000 Jan 1 + +static const s32 sDaysPerMonth[] = { + [MONTH_JAN - 1] = 31, + [MONTH_FEB - 1] = 28, + [MONTH_MAR - 1] = 31, + [MONTH_APR - 1] = 30, + [MONTH_MAY - 1] = 31, + [MONTH_JUN - 1] = 30, + [MONTH_JUL - 1] = 31, + [MONTH_AUG - 1] = 31, + [MONTH_SEP - 1] = 30, + [MONTH_OCT - 1] = 31, + [MONTH_NOV - 1] = 30, + [MONTH_DEC - 1] = 31 }; -void rtc_get_status_and_datetime(struct SiiRtcInfo *); -u16 rtc_validate_datetime(struct SiiRtcInfo *); +static void RtcGetRawInfo(struct SiiRtcInfo *); +static u16 RtcCheckInfo(struct SiiRtcInfo *); - -void rtc_intr_disable(void) +static void RtcDisableInterrupts(void) { - sImeBak = REG_IME; + sSavedIme = REG_IME; REG_IME = 0; } -void rtc_intr_enable(void) +static void RtcRestoreInterrupts(void) { - REG_IME = sImeBak; + REG_IME = sSavedIme; } -s32 bcd_to_hex(u8 a0) +static s32 ConvertBcdToBinary(u8 bcd) { - if (a0 >= 0xa0 || (a0 & 0xF) >= 10) + if (bcd >= 0xa0 || (bcd & 0xF) >= 10) return 0xFF; - return ((a0 >> 4) & 0xF) * 10 + (a0 & 0xF); + return ((bcd >> 4) & 0xF) * 10 + (bcd & 0xF); } -bool8 is_leap_year(u8 year) +static bool8 IsLeapYear(u8 year) { if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return TRUE; return FALSE; } -u16 rtc_count_days_parameterized(u8 year, u8 month, u8 day) +static u16 ConvertDateToDayCount(u8 year, u8 month, u8 day) { - u16 numDays = 0; s32 i; + u16 dayCount = 0; + for (i = year - 1; i > 0; i--) { - numDays += 365; - if (is_leap_year(i) == TRUE) - numDays++; + dayCount += 365; + + if (IsLeapYear(i) == TRUE) + dayCount++; } + for (i = 0; i < month - 1; i++) - numDays += sDaysPerMonth[i]; - if (month > MONTH_FEB && is_leap_year(year) == TRUE) - numDays++; - numDays += day; - return numDays; + dayCount += sDaysPerMonth[i]; + + if (month > MONTH_FEB && IsLeapYear(year) == TRUE) + dayCount++; + + dayCount += day; + + return dayCount; } -u16 rtc_count_days_from_info(struct SiiRtcInfo *info) +u16 RtcGetDayCount(struct SiiRtcInfo *rtc) { - return rtc_count_days_parameterized(bcd_to_hex(info->year), bcd_to_hex(info->month), bcd_to_hex(info->day)); -} + u8 year = ConvertBcdToBinary(rtc->year); + u8 month = ConvertBcdToBinary(rtc->month); + u8 day = ConvertBcdToBinary(rtc->day); + return ConvertDateToDayCount(year, month, day);} -static void rtc_probe_status(void) +static void RtcInit(void) { - sRtcProbeStatus = 0; - rtc_intr_disable(); + sErrorStatus = 0; + + RtcDisableInterrupts(); SiiRtcUnprotect(); - sRtcProbeCode = SiiRtcProbe(); - rtc_intr_enable(); - if ((sRtcProbeCode & 0xF) != 1) - sRtcProbeStatus = 1; - else + sProbeResult = SiiRtcProbe(); + RtcRestoreInterrupts(); + + if ((sProbeResult & 0xF) != 1) { - if (sRtcProbeCode & 0xF0) - sRtcProbeStatus = 2; - else - sRtcProbeStatus = 0; - rtc_get_status_and_datetime(&sRtcInfoBuffer); - sRtcProbeStatus = rtc_validate_datetime(&sRtcInfoBuffer); + sErrorStatus = RTC_INIT_ERROR; + return; } -} -u16 rtc_get_probe_status(void) -{ - return sRtcProbeStatus; -} - -void sub_020106EC(struct SiiRtcInfo * info) -{ - if (sRtcProbeStatus & 0xFF0) - *info = sDefaultRTC; + if (sProbeResult & 0xF0) + sErrorStatus = RTC_INIT_WARNING; else - rtc_get_status_and_datetime(info); + sErrorStatus = 0; + + RtcGetRawInfo(&sRtcInfoBuffer); + sErrorStatus = RtcCheckInfo(&sRtcInfoBuffer); } -void rtc_get_datetime(struct SiiRtcInfo * info) +static u16 RtcGetErrorStatus(void) { - rtc_intr_disable(); - SiiRtcGetDateTime(info); - rtc_intr_enable(); + return sErrorStatus; } -void rtc_get_status(struct SiiRtcInfo * info) +// Unused +static void RtcGetInfo(struct SiiRtcInfo * rtc) { - rtc_intr_disable(); - SiiRtcGetStatus(info); - rtc_intr_enable(); + if (sErrorStatus & 0xFF0) + *rtc = sDefaultRTC; + else + RtcGetRawInfo(rtc); } -void rtc_get_status_and_datetime(struct SiiRtcInfo * info) +static void RtcGetDateTime(struct SiiRtcInfo * rtc) { - rtc_get_status(info); - rtc_get_datetime(info); + RtcDisableInterrupts(); + SiiRtcGetDateTime(rtc); + RtcRestoreInterrupts(); } -u16 rtc_validate_datetime(struct SiiRtcInfo * info) +static void RtcGetStatus(struct SiiRtcInfo * rtc) { - s32 year, month, day; - u16 r4 = (info->status & SIIRTCINFO_POWER) ? 0x20 : 0; - if (!(info->status & SIIRTCINFO_24HOUR)) - r4 |= 0x10; - year = bcd_to_hex(info->year); + RtcDisableInterrupts(); + SiiRtcGetStatus(rtc); + RtcRestoreInterrupts(); +} + +static void RtcGetRawInfo(struct SiiRtcInfo * rtc) +{ + RtcGetStatus(rtc); + RtcGetDateTime(rtc); +} + +static u16 RtcCheckInfo(struct SiiRtcInfo * rtc) +{ + u16 errorFlags = 0; + s32 year; + s32 month; + s32 value; + + if (rtc->status & SIIRTCINFO_POWER) + errorFlags |= RTC_ERR_POWER_FAILURE; + + if (!(rtc->status & SIIRTCINFO_24HOUR)) + errorFlags |= RTC_ERR_12HOUR_CLOCK; + + year = ConvertBcdToBinary(rtc->year); if (year == 0xFF) - r4 |= 0x40; - month = bcd_to_hex(info->month); + errorFlags |= RTC_ERR_INVALID_YEAR; + + month = ConvertBcdToBinary(rtc->month); if (month == 0xFF || month == 0 || month > 12) - r4 |= 0x80; - day = bcd_to_hex(info->day); - if (day == 0xFF) - r4 |= 0x100; + errorFlags |= RTC_ERR_INVALID_MONTH; + + value = ConvertBcdToBinary(rtc->day); + if (value == 0xFF) + errorFlags |= RTC_ERR_INVALID_DAY; + if (month == MONTH_FEB) { - if (day > is_leap_year(year) + sDaysPerMonth[1]) - r4 |= 0x100; + if (value > IsLeapYear(year) + sDaysPerMonth[1]) + errorFlags |= RTC_ERR_INVALID_DAY; } else { - if (day > sDaysPerMonth[month - 1]) - r4 |= 0x100; + if (value > sDaysPerMonth[month - 1]) + errorFlags |= RTC_ERR_INVALID_DAY; } - day = bcd_to_hex(info->hour); - if (day > 24) - r4 |= 0x200; - day = bcd_to_hex(info->minute); - if (day > 60) - r4 |= 0x400; - day = bcd_to_hex(info->second); - if (day > 60) - r4 |= 0x800; - return r4; + + value = ConvertBcdToBinary(rtc->hour); + if (value > 24) + errorFlags |= RTC_ERR_INVALID_HOUR; + + value = ConvertBcdToBinary(rtc->minute); + if (value > 60) + errorFlags |= RTC_ERR_INVALID_MINUTE; + + value = ConvertBcdToBinary(rtc->second); + if (value > 60) + errorFlags |= RTC_ERR_INVALID_SECOND; + + return errorFlags; } -void rtc_reset(void) +// Unused +static void RtcReset(void) { - rtc_intr_disable(); + RtcDisableInterrupts(); SiiRtcReset(); - rtc_intr_enable(); + RtcRestoreInterrupts(); } -void rtc_sub_time_from_datetime(struct SiiRtcInfo * datetime, struct Time * dest, struct Time * timediff) +static void RtcCalcTimeDifference(struct SiiRtcInfo * rtc, struct Time * result, struct Time * t) { - u16 r4 = rtc_count_days_from_info(datetime); - dest->seconds = bcd_to_hex(datetime->second) - timediff->seconds; - dest->minutes = bcd_to_hex(datetime->minute) - timediff->minutes; - dest->hours = bcd_to_hex(datetime->hour) - timediff->hours; - dest->days = r4 - timediff->days; - if (dest->seconds < 0) + u16 days = RtcGetDayCount(rtc); + result->seconds = ConvertBcdToBinary(rtc->second) - t->seconds; + result->minutes = ConvertBcdToBinary(rtc->minute) - t->minutes; + result->hours = ConvertBcdToBinary(rtc->hour) - t->hours; + result->days = days - t->days; + + if (result->seconds < 0) { - dest->seconds += 60; - dest->minutes--; + result->seconds += 60; + result->minutes--; } - if (dest->minutes < 0) + + if (result->minutes < 0) { - dest->minutes += 60; - dest->hours--; + result->minutes += 60; + result->hours--; } - if (dest->hours < 0) + + if (result->hours < 0) { - dest->hours += 24; - dest->days--; + result->hours += 24; + result->days--; } } -void rtc_sub_time_from_time(struct Time * dest, struct Time * diff, struct Time * src) +static void CalcTimeDifference(struct Time * result, struct Time * t1, struct Time * t2) { - dest->seconds = src->seconds - diff->seconds; - dest->minutes = src->minutes - diff->minutes; - dest->hours = src->hours - diff->hours; - dest->days = src->days - diff->days; - if (dest->seconds < 0) + result->seconds = t2->seconds - t1->seconds; + result->minutes = t2->minutes - t1->minutes; + result->hours = t2->hours - t1->hours; + result->days = t2->days - t1->days; + + if (result->seconds < 0) { - dest->seconds += 60; - dest->minutes--; + result->seconds += 60; + result->minutes--; } - if (dest->minutes < 0) + + if (result->minutes < 0) { - dest->minutes += 60; - dest->hours--; + result->minutes += 60; + result->hours--; } - if (dest->hours < 0) + + if (result->hours < 0) { - dest->hours += 24; - dest->days--; + result->hours += 24; + result->days--; } } bool32 rtc_maincb_is_rtc_working(void) { - rtc_probe_status(); - if (rtc_get_probe_status() & 0xFF0) + RtcInit(); + if (RtcGetErrorStatus() & 0xFF0) return FALSE; return TRUE; } -void rtc_set_datetime(struct SiiRtcInfo * info) +void rtc_set_datetime(struct SiiRtcInfo * rtc) { vu16 imeBak = REG_IME; REG_IME = 0; - SiiRtcSetDateTime(info); + SiiRtcSetDateTime(rtc); REG_IME = imeBak; } bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 * year) { - rtc_get_status_and_datetime(&sRtcInfoWork); - *year = bcd_to_hex(sRtcInfoWork.year); - rtc_sub_time_from_datetime(&sRtcInfoWork, &gRtcUTCTime, LocalTimeOffset); - rtc_sub_time_from_time(&gTimeSinceBerryUpdate, LastBerryTreeUpdate, &gRtcUTCTime); + RtcGetRawInfo(&sRtcInfoWork); + *year = ConvertBcdToBinary(sRtcInfoWork.year); + RtcCalcTimeDifference(&sRtcInfoWork, &gRtcUTCTime, LocalTimeOffset); + CalcTimeDifference(&gTimeSinceBerryUpdate, LastBerryTreeUpdate, &gRtcUTCTime); if (gTimeSinceBerryUpdate.days * 1440 + gTimeSinceBerryUpdate.hours * 60 + gTimeSinceBerryUpdate.minutes >= 0) return TRUE; return FALSE; } -u32 hex_to_bcd(u8 a0) +static u32 ConvertBinaryToBcd(u8 binary) { - u32 r4; - if (a0 > 99) + u32 bcd; + if (binary > 99) return 0xFF; - r4 = Div(a0, 10) << 4; - r4 |= Mod(a0, 10); - return r4; + bcd = Div(binary, 10) << 4; + bcd |= Mod(binary, 10); + return bcd; } void sii_rtc_inc(u8 * a0) { - *a0 = hex_to_bcd(bcd_to_hex(*a0) + 1); + *a0 = ConvertBinaryToBcd(ConvertBcdToBinary(*a0) + 1); } void sii_rtc_inc_month(struct SiiRtcInfo * a0) { sii_rtc_inc(&a0->month); - if (bcd_to_hex(a0->month) > 12) + if (ConvertBcdToBinary(a0->month) > 12) { sii_rtc_inc(&a0->year); a0->month = MONTH_JAN; @@ -290,9 +313,9 @@ void sii_rtc_inc_month(struct SiiRtcInfo * a0) void sii_rtc_inc_day(struct SiiRtcInfo * a0) { sii_rtc_inc(&a0->day); - if (bcd_to_hex(a0->day) > sDaysPerMonth[bcd_to_hex(a0->month) - 1]) + if (ConvertBcdToBinary(a0->day) > sDaysPerMonth[ConvertBcdToBinary(a0->month) - 1]) { - if (!is_leap_year(bcd_to_hex(a0->year)) || bcd_to_hex(a0->month) != MONTH_FEB || bcd_to_hex(a0->day) != 29) + if (!IsLeapYear(ConvertBcdToBinary(a0->year)) || ConvertBcdToBinary(a0->month) != MONTH_FEB || ConvertBcdToBinary(a0->day) != 29) { a0->day = 1; sii_rtc_inc_month(a0); @@ -302,27 +325,27 @@ void sii_rtc_inc_day(struct SiiRtcInfo * a0) bool32 rtc_is_past_feb_28_2000(struct SiiRtcInfo * a0) { - if (bcd_to_hex(a0->year) == 0) + if (ConvertBcdToBinary(a0->year) == 0) { - if (bcd_to_hex(a0->month) == MONTH_JAN) + if (ConvertBcdToBinary(a0->month) == MONTH_JAN) return FALSE; - if (bcd_to_hex(a0->month) > MONTH_FEB) + if (ConvertBcdToBinary(a0->month) > MONTH_FEB) return TRUE; - if (bcd_to_hex(a0->day) == 29) + if (ConvertBcdToBinary(a0->day) == 29) return TRUE; return FALSE; } - if (bcd_to_hex(a0->year) == 1) + if (ConvertBcdToBinary(a0->year) == 1) return TRUE; return FALSE; } void rtc_maincb_fix_date(void) { - rtc_get_status_and_datetime(&sRtcInfoWork); - if (bcd_to_hex(sRtcInfoWork.year) == 0 || bcd_to_hex(sRtcInfoWork.year) == 1) + RtcGetRawInfo(&sRtcInfoWork); + if (ConvertBcdToBinary(sRtcInfoWork.year) == 0 || ConvertBcdToBinary(sRtcInfoWork.year) == 1) { - if (bcd_to_hex(sRtcInfoWork.year) == 1) + if (ConvertBcdToBinary(sRtcInfoWork.year) == 1) { sRtcInfoWork.year = 2; sRtcInfoWork.month = MONTH_JAN; @@ -343,4 +366,4 @@ void rtc_maincb_fix_date(void) rtc_set_datetime(&sRtcInfoWork); } } -} +} \ No newline at end of file From e2c53310518e14420b95beba77aa4c4a2c663745 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 14:57:41 -0500 Subject: [PATCH 10/12] Clean up rtc --- payload/include/global.h | 18 ++++----- payload/include/rtc.h | 6 +-- payload/src/event_data.c | 4 +- payload/src/main.c | 6 +-- payload/src/rtc.c | 79 ++++++++++++++++++++++++---------------- 5 files changed, 62 insertions(+), 51 deletions(-) diff --git a/payload/include/global.h b/payload/include/global.h index 9762dd6..b59ff3d 100644 --- a/payload/include/global.h +++ b/payload/include/global.h @@ -26,13 +26,6 @@ #define RomHeaderMagic ((const u8 *) 0x080000B2) #define RomHeaderSoftwareVersion ((const u8 *) 0x080000BC) -#define LocalTimeOffset ((struct Time *)0x02028098) -#define LastBerryTreeUpdate ((struct Time *)0x020280A0) - -#define POKEMON_SLOTS_NUMBER 412 -#define POKEMON_NAME_LENGTH 10 -#define OT_NAME_LENGTH 7 - #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) >= (b) ? (a) : (b)) @@ -59,19 +52,22 @@ struct Time }; // Dummy Ruby/Sapphire save structs. -// Only the vars array in SaveBlock1 (for VAR_PACIFIDLOG_TM_RECEIVED_DAY specifically) is needed for the Berry Fix Program. +// Only vars, localTimeOffset, and lastBerryTreeUpdate are needed. struct SaveBlock1 { - u8 dummy_PreVars[0x1340]; + u8 dummy_0[0x1340]; u16 vars[VARS_COUNT]; - u8 dummy_PostVars[0x2580]; + u8 dummy_1[0x2580]; }; extern struct SaveBlock1 gSaveBlock1; struct SaveBlock2 { - u8 dummy[0x890]; + u8 dummy_0[0x98]; + struct Time localTimeOffset; + struct Time lastBerryTreeUpdate; + u8 dummy_1[0x7E8]; }; extern struct SaveBlock2 gSaveBlock2; diff --git a/payload/include/rtc.h b/payload/include/rtc.h index 2ac6960..daaa1b3 100644 --- a/payload/include/rtc.h +++ b/payload/include/rtc.h @@ -18,8 +18,8 @@ extern struct Time gTimeSinceBerryUpdate; extern struct Time gRtcUTCTime; -bool32 rtc_maincb_is_rtc_working(void); -bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 *); -void rtc_maincb_fix_date(void); +bool32 BerryFix_TryInitRtc(void); +bool32 BerryFix_CalcTimeDifference(u8 *); +void BerryFix_SetDate(void); #endif //GUARD_RTC_H diff --git a/payload/src/event_data.c b/payload/src/event_data.c index f7162a3..c636c53 100644 --- a/payload/src/event_data.c +++ b/payload/src/event_data.c @@ -31,7 +31,7 @@ bool32 BerryFix_ShouldResetPacifidlogTM(void) { u8 year; u16 * var = GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY); - rtc_maincb_is_time_since_last_berry_update_positive(&year); + BerryFix_CalcTimeDifference(&year); if (*var <= gRtcUTCTime.days) return TRUE; else @@ -43,7 +43,7 @@ bool32 BerryFix_ResetPacifidlogTM(void) u8 year; if (BerryFix_ShouldResetPacifidlogTM() == TRUE) return TRUE; - rtc_maincb_is_time_since_last_berry_update_positive(&year); + BerryFix_CalcTimeDifference(&year); if (gRtcUTCTime.days < 0) return FALSE; *GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1; diff --git a/payload/src/main.c b/payload/src/main.c index bb78e7d..272c209 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -196,7 +196,7 @@ void main_callback(u32 * state, void * unused1, void * unused2) } break; case MAINCB_CHECK_RTC: - if (!rtc_maincb_is_rtc_working()) + if (!BerryFix_TryInitRtc()) *state = MAINCB_ERROR; else ++(*state); // MAINCB_CHECK_FLASH @@ -214,7 +214,7 @@ void main_callback(u32 * state, void * unused1, void * unused2) *state = MAINCB_ERROR; break; case MAINCB_CHECK_TIME: - if (rtc_maincb_is_time_since_last_berry_update_positive(&year) == TRUE) + if (BerryFix_CalcTimeDifference(&year) == TRUE) { if (year == 0) ++(*state); // MAINCB_FIX_DATE @@ -230,7 +230,7 @@ void main_callback(u32 * state, void * unused1, void * unused2) } break; case MAINCB_FIX_DATE: - rtc_maincb_fix_date(); + BerryFix_SetDate(); gUpdateSuccessful |= 1; *state = MAINCB_CHECK_PACIFIDLOG_TM; break; diff --git a/payload/src/rtc.c b/payload/src/rtc.c index a4f2fd8..7f2571b 100644 --- a/payload/src/rtc.c +++ b/payload/src/rtc.c @@ -120,7 +120,7 @@ static u16 RtcGetErrorStatus(void) // Unused static void RtcGetInfo(struct SiiRtcInfo * rtc) { - if (sErrorStatus & 0xFF0) + if (sErrorStatus & RTC_ERR_FLAG_MASK) *rtc = sDefaultRTC; else RtcGetRawInfo(rtc); @@ -258,15 +258,17 @@ static void CalcTimeDifference(struct Time * result, struct Time * t1, struct Ti } } -bool32 rtc_maincb_is_rtc_working(void) +// New code for Berry Fix Program starts here + +bool32 BerryFix_TryInitRtc(void) { RtcInit(); - if (RtcGetErrorStatus() & 0xFF0) + if (RtcGetErrorStatus() & RTC_ERR_FLAG_MASK) return FALSE; return TRUE; } -void rtc_set_datetime(struct SiiRtcInfo * rtc) +static void RtcSetDateTime(struct SiiRtcInfo * rtc) { vu16 imeBak = REG_IME; REG_IME = 0; @@ -274,13 +276,19 @@ void rtc_set_datetime(struct SiiRtcInfo * rtc) REG_IME = imeBak; } -bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 * year) +// The below are equivalent to &gSaveBlock2.localTimeOffset and &gSaveBlock2.lastBerryTreeUpdate. +// Replacing them both below doesn't match +#define SaveBlock2Addr (EWRAM_START + 0x28000) +#define LocalTimeOffset ((struct Time *)(SaveBlock2Addr + offsetof(struct SaveBlock2, localTimeOffset))) +#define LastBerryTreeUpdate ((struct Time *)(SaveBlock2Addr + offsetof(struct SaveBlock2, lastBerryTreeUpdate))) + +bool32 BerryFix_CalcTimeDifference(u8 * year) { RtcGetRawInfo(&sRtcInfoWork); *year = ConvertBcdToBinary(sRtcInfoWork.year); RtcCalcTimeDifference(&sRtcInfoWork, &gRtcUTCTime, LocalTimeOffset); CalcTimeDifference(&gTimeSinceBerryUpdate, LastBerryTreeUpdate, &gRtcUTCTime); - if (gTimeSinceBerryUpdate.days * 1440 + gTimeSinceBerryUpdate.hours * 60 + gTimeSinceBerryUpdate.minutes >= 0) + if (gTimeSinceBerryUpdate.days * 24 * 60 + gTimeSinceBerryUpdate.hours * 60 + gTimeSinceBerryUpdate.minutes >= 0) return TRUE; return FALSE; } @@ -295,75 +303,82 @@ static u32 ConvertBinaryToBcd(u8 binary) return bcd; } -void sii_rtc_inc(u8 * a0) +static void RtcIncrement(u8 * val) { - *a0 = ConvertBinaryToBcd(ConvertBcdToBinary(*a0) + 1); + *val = ConvertBinaryToBcd(ConvertBcdToBinary(*val) + 1); } -void sii_rtc_inc_month(struct SiiRtcInfo * a0) +static void RtcIncrementMonth(struct SiiRtcInfo * rtc) { - sii_rtc_inc(&a0->month); - if (ConvertBcdToBinary(a0->month) > 12) + RtcIncrement(&rtc->month); + if (ConvertBcdToBinary(rtc->month) > 12) { - sii_rtc_inc(&a0->year); - a0->month = MONTH_JAN; + RtcIncrement(&rtc->year); + rtc->month = MONTH_JAN; } } -void sii_rtc_inc_day(struct SiiRtcInfo * a0) +static void RtcIncrementDay(struct SiiRtcInfo * rtc) { - sii_rtc_inc(&a0->day); - if (ConvertBcdToBinary(a0->day) > sDaysPerMonth[ConvertBcdToBinary(a0->month) - 1]) + RtcIncrement(&rtc->day); + if (ConvertBcdToBinary(rtc->day) > sDaysPerMonth[ConvertBcdToBinary(rtc->month) - 1]) { - if (!IsLeapYear(ConvertBcdToBinary(a0->year)) || ConvertBcdToBinary(a0->month) != MONTH_FEB || ConvertBcdToBinary(a0->day) != 29) + if (!IsLeapYear(ConvertBcdToBinary(rtc->year)) || ConvertBcdToBinary(rtc->month) != MONTH_FEB || ConvertBcdToBinary(rtc->day) != 29) { - a0->day = 1; - sii_rtc_inc_month(a0); + rtc->day = 1; + RtcIncrementMonth(rtc); } } } -bool32 rtc_is_past_feb_28_2000(struct SiiRtcInfo * a0) +// When fixing the RTC, consider if the leap day on Feb 29, 2000 was reached +static bool32 RtcNeedsLeapDayIncrement(struct SiiRtcInfo * rtc) { - if (ConvertBcdToBinary(a0->year) == 0) + if (ConvertBcdToBinary(rtc->year) == 0) { - if (ConvertBcdToBinary(a0->month) == MONTH_JAN) + if (ConvertBcdToBinary(rtc->month) == MONTH_JAN) return FALSE; - if (ConvertBcdToBinary(a0->month) > MONTH_FEB) + if (ConvertBcdToBinary(rtc->month) > MONTH_FEB) return TRUE; - if (ConvertBcdToBinary(a0->day) == 29) + if (ConvertBcdToBinary(rtc->day) == 29) return TRUE; return FALSE; } - if (ConvertBcdToBinary(a0->year) == 1) + if (ConvertBcdToBinary(rtc->year) == 1) return TRUE; + + // After 2001 just set clock forward 365 days return FALSE; } -void rtc_maincb_fix_date(void) +void BerryFix_SetDate(void) { RtcGetRawInfo(&sRtcInfoWork); if (ConvertBcdToBinary(sRtcInfoWork.year) == 0 || ConvertBcdToBinary(sRtcInfoWork.year) == 1) { if (ConvertBcdToBinary(sRtcInfoWork.year) == 1) { + // Year is 2001, the Berry Glitch is occurring + // Set date forward to January 2, 2002 sRtcInfoWork.year = 2; sRtcInfoWork.month = MONTH_JAN; sRtcInfoWork.day = 2; - rtc_set_datetime(&sRtcInfoWork); + RtcSetDateTime(&sRtcInfoWork); } else { - if (rtc_is_past_feb_28_2000(&sRtcInfoWork) == TRUE) + // Berry Glitch hasn't begun yet (or was already passed) + // Set the date forward 365/366 days to avoid the glitch + if (RtcNeedsLeapDayIncrement(&sRtcInfoWork) == TRUE) { - sii_rtc_inc_day(&sRtcInfoWork); - sii_rtc_inc(&sRtcInfoWork.year); + RtcIncrementDay(&sRtcInfoWork); + RtcIncrement(&sRtcInfoWork.year); } else { - sii_rtc_inc(&sRtcInfoWork.year); + RtcIncrement(&sRtcInfoWork.year); } - rtc_set_datetime(&sRtcInfoWork); + RtcSetDateTime(&sRtcInfoWork); } } } \ No newline at end of file From b03c802e01eaf41c5b8e3da0e9f1abf6202fc9ba Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 15:01:18 -0500 Subject: [PATCH 11/12] Clean up main.c --- payload/common_syms/main.txt | 4 +- payload/include/event_data.h | 2 +- payload/include/main.h | 38 ---- payload/include/rtc.h | 2 +- payload/src/event_data.c | 4 +- payload/src/main.c | 373 ++++++++++++++++++++--------------- payload/src/rtc.c | 8 +- 7 files changed, 226 insertions(+), 205 deletions(-) diff --git a/payload/common_syms/main.txt b/payload/common_syms/main.txt index b62c721..a1a1402 100644 --- a/payload/common_syms/main.txt +++ b/payload/common_syms/main.txt @@ -3,7 +3,7 @@ gHeldKeys gNewKeys gIntrVector gUpdateSuccessful -gUnknown_3001194 -gUnknown_30011A0 +gUnusedVar +gUnusedBuffer gMainCallbackState gGameVersion diff --git a/payload/include/event_data.h b/payload/include/event_data.h index db83834..c0668f7 100644 --- a/payload/include/event_data.h +++ b/payload/include/event_data.h @@ -1,7 +1,7 @@ #ifndef GUARD_EVENT_DATA_H #define GUARD_EVENT_DATA_H -bool32 BerryFix_ShouldResetPacifidlogTM(void); +bool32 BerryFix_IsPacifidlogTMCorrect(void); bool32 BerryFix_ResetPacifidlogTM(void); #endif //GUARD_EVENT_DATA_H diff --git a/payload/include/main.h b/payload/include/main.h index cb58d59..0b74434 100644 --- a/payload/include/main.h +++ b/payload/include/main.h @@ -1,45 +1,7 @@ #ifndef GUARD_MAIN_H #define GUARD_MAIN_H -#include "gba/gba.h" - -enum RomHeaderValidationResult -{ - SAPPHIRE_UPDATABLE = 2, - RUBY_UPDATABLE, - SAPPHIRE_NONEED, - RUBY_NONEED, - INVALID -}; - -enum MainCallbackState -{ - MAINCB_INIT = 0, - MAINCB_CHECK_RTC, - MAINCB_CHECK_FLASH, - MAINCB_READ_SAVE, - MAINCB_CHECK_TIME, - MAINCB_FIX_DATE, - MAINCB_NO_NEED_TO_FIX, - MAINCB_YEAR_MAKES_NO_SENSE, - MAINCB_FINISHED, - MAINCB_CHECK_PACIFIDLOG_TM, - MAINCB_FIX_PACIFIDLOG_TM, - MAINCB_ERROR -}; - extern IntrFunc gIntrTable[]; -extern u16 gHeldKeys; -extern u16 gNewKeys; -extern u8 gIntrVector[]; -extern u32 gUpdateSuccessful; -extern u32 gUnknown_3001194; -extern u32 gUnknown_30011A0[]; -extern u32 gMainCallbackState; -extern u32 gGameVersion; - -extern u8 gSharedMem[0x8000]; - extern const IntrFunc gIntrFuncPointers[]; #endif //GUARD_MAIN_H diff --git a/payload/include/rtc.h b/payload/include/rtc.h index daaa1b3..bef6262 100644 --- a/payload/include/rtc.h +++ b/payload/include/rtc.h @@ -19,7 +19,7 @@ extern struct Time gTimeSinceBerryUpdate; extern struct Time gRtcUTCTime; bool32 BerryFix_TryInitRtc(void); +void BerryFix_TryFixDate(void); bool32 BerryFix_CalcTimeDifference(u8 *); -void BerryFix_SetDate(void); #endif //GUARD_RTC_H diff --git a/payload/src/event_data.c b/payload/src/event_data.c index c636c53..a2bd4e1 100644 --- a/payload/src/event_data.c +++ b/payload/src/event_data.c @@ -27,7 +27,7 @@ static u16 * GetVarPointer(u16 id) return NULL; } -bool32 BerryFix_ShouldResetPacifidlogTM(void) +bool32 BerryFix_IsPacifidlogTMCorrect(void) { u8 year; u16 * var = GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY); @@ -41,7 +41,7 @@ bool32 BerryFix_ShouldResetPacifidlogTM(void) bool32 BerryFix_ResetPacifidlogTM(void) { u8 year; - if (BerryFix_ShouldResetPacifidlogTM() == TRUE) + if (BerryFix_IsPacifidlogTMCorrect() == TRUE) return TRUE; BerryFix_CalcTimeDifference(&year); if (gRtcUTCTime.days < 0) diff --git a/payload/src/main.c b/payload/src/main.c index 272c209..a2b3ef8 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -1,4 +1,3 @@ -#include "gba/gba.h" #include "global.h" #include "main.h" #include "rtc.h" @@ -6,43 +5,75 @@ #include "event_data.h" #include "message_box.h" -static s32 gInitialWaitTimer; +#define ROM_HEADER_MAGIC 0x96 +#define ROM_GAME_TITLE_LEN 15 + +// States for the main BerryFix function +enum { + STATE_INIT, + STATE_CHECK_RTC, + STATE_CHECK_FLASH, + STATE_READ_SAVE, + STATE_CHECK_TIME, + STATE_FIX_DATE, + STATE_NO_NEED_TO_FIX, + STATE_ERROR_YEAR, + STATE_FINISHED, + STATE_CHECK_PACIFIDLOG_TM, + STATE_FIX_PACIFIDLOG_TM, + STATE_ERROR +}; + +// Return values for ValidateRomHeader +enum +{ + UPDATE_SAPPHIRE = 2, + UPDATE_RUBY, + NO_UPDATE_SAPPHIRE, + NO_UPDATE_RUBY, + INVALID +}; + +static s32 sInitialWaitTimer; IntrFunc gIntrTable[16]; u16 gHeldKeys; u16 gNewKeys; u8 gIntrVector[0x100]; u32 gUpdateSuccessful; -u32 gUnknown_3001194; -u32 gUnknown_30011A0[0x19]; +u32 gUnusedVar; +u32 gUnusedBuffer[25]; u32 gMainCallbackState; u32 gGameVersion; -EWRAM_DATA u8 gSharedMem[0x8000] = {}; +static EWRAM_DATA u8 sSharedMem[0x8000] = {}; -void IntrMain(void); -void ReadKeys(void); -void dummy_intr_0(void); -void dummy_intr_1(void); -void main_callback(u32 *, void *, void *); +extern void IntrMain(void); +static void ReadKeys(void); +static void IntrDummy(void); +static void SerialIntr(void); +static void BerryFix(u32 *, void *, void *); + +static const char sBerryFixGameCode[] = "AGBJ"; -const char gBerryFixGameCode[] = "AGBJ"; const IntrFunc gIntrFuncPointers[] = { - dummy_intr_0, - dummy_intr_1, - dummy_intr_0, - dummy_intr_0, - dummy_intr_0, - dummy_intr_0, - dummy_intr_0, - dummy_intr_0, - dummy_intr_0, - dummy_intr_0, + IntrDummy, + SerialIntr, + IntrDummy, + IntrDummy, + IntrDummy, + IntrDummy, + IntrDummy, + IntrDummy, + IntrDummy, + IntrDummy, + NULL, NULL, NULL, - NULL }; -const char gVersionData[][2] = { + +// Language character code, followed by version number +static const char sVersionData[][2] = { {'J', 1}, {'E', 2}, {'D', 1}, @@ -50,230 +81,255 @@ const char gVersionData[][2] = { {'I', 1}, {'S', 1} }; -const char gRubyTitleAndCode[] = "POKEMON RUBYAXV"; -const char gSapphireTitleAndCode[] = "POKEMON SAPPAXP"; -const u16 sDebugPals[20] = { - RGB(00, 00, 00), - RGB(31, 00, 00), - RGB(00, 31, 00), - RGB(00, 00, 31) +static const char sRubyTitleAndCode[ROM_GAME_TITLE_LEN] = "POKEMON RUBYAXV"; +static const char sSapphireTitleAndCode[ROM_GAME_TITLE_LEN] = "POKEMON SAPPAXP"; +static const u16 sDebugPals[20] = { + RGB_BLACK, + RGB_RED, + RGB_GREEN, + RGB_BLUE }; -const u16 sDebugDigitsGfx[] = INCBIN_U16("graphics/debug_digits.4bpp"); +static const u16 sDebugDigitsGfx[] = INCBIN_U16("graphics/debug_digits.4bpp"); void AgbMain(void) { - RegisterRamReset(0x1E); - DmaCopy32(3, gIntrFuncPointers, gIntrTable, sizeof gIntrFuncPointers); + RegisterRamReset(RESET_IWRAM | RESET_PALETTE | RESET_VRAM | RESET_OAM); + DmaCopy32(3, gIntrFuncPointers, gIntrTable, sizeof(gIntrFuncPointers)); DmaCopy32(3, IntrMain, gIntrVector, sizeof(gIntrVector)); INTR_VECTOR = gIntrVector; REG_IE = INTR_FLAG_VBLANK; - if (*RomHeaderMagic == 0x96 && *(u32 *)RomHeaderGameCode == *(u32 *)gBerryFixGameCode) + if (*RomHeaderMagic == ROM_HEADER_MAGIC && *(u32 *)RomHeaderGameCode == *(u32 *)sBerryFixGameCode) REG_IE |= INTR_FLAG_GAMEPAK; REG_DISPSTAT = DISPSTAT_VBLANK_INTR; REG_IME = INTR_FLAG_VBLANK; MessageBox_Load(); - gMainCallbackState = MAINCB_INIT; - gUnknown_3001194 = 0; + gMainCallbackState = STATE_INIT; + gUnusedVar = 0; for (;;) { VBlankIntrWait(); ReadKeys(); - main_callback(&gMainCallbackState, gUnknown_30011A0, gSharedMem); + BerryFix(&gMainCallbackState, gUnusedBuffer, sSharedMem); } } -void dummy_intr_1(void) +static void SerialIntr(void) {} -void dummy_intr_0(void) +static void IntrDummy(void) {} -void ReadKeys(void) +static void ReadKeys(void) { u16 keyInput = REG_KEYINPUT ^ KEYS_MASK; gNewKeys = keyInput & ~gHeldKeys; gHeldKeys = keyInput; } -void fill_palette(const u8 * src, u16 * dest, u8 value) +// Unused +static void fill_palette(const u8 * src, u16 * dest, u8 value) { s32 i; for (i = 0; src[i] != 0; i++) dest[i] = src[i] | value << 12; } -bool32 berry_fix_memcmp(const char * src1, const char * src2, size_t size) +static bool32 CheckSameString(const char * a, const char * b, size_t size) { s32 i; for (i = 0; i < size; i++) { - if (src1[i] != src2[i]) + if (a[i] != b[i]) return FALSE; } return TRUE; } -s32 validate_rom_header_internal(void) +static s32 ValidateGameVersion(void) { - char languageCode = *(RomHeaderGameCode + 3); + char languageCode = RomHeaderGameCode[3]; s32 softwareVersion = *RomHeaderSoftwareVersion; s32 shouldUpdate = -1; s32 i; - for (i = 0; i < ARRAY_COUNT(gVersionData); i++) + + // Check rom header data to see if games of this + // language and revision need the berry fix. + for (i = 0; i < ARRAY_COUNT(sVersionData); i++) { - if (languageCode == gVersionData[i][0]) + if (languageCode == sVersionData[i][0]) { - if (softwareVersion >= gVersionData[i][1]) - { - shouldUpdate = 0; - } + if (softwareVersion >= sVersionData[i][1]) + shouldUpdate = FALSE; else - { - shouldUpdate = 1; - } + shouldUpdate = TRUE; break; } } if (shouldUpdate != -1) { - if (berry_fix_memcmp(RomHeaderGameTitle, gRubyTitleAndCode, 15) == TRUE) + // A valid language/revision was found, check game title + // and code to see if it's Ruby or Sapphire + + if (CheckSameString(RomHeaderGameTitle, sRubyTitleAndCode, ROM_GAME_TITLE_LEN) == TRUE) { - if (shouldUpdate == 0) - return RUBY_NONEED; + if (shouldUpdate == FALSE) + { + return NO_UPDATE_RUBY; + } else { gGameVersion = VERSION_RUBY; - return RUBY_UPDATABLE; + return UPDATE_RUBY; } } - else if (berry_fix_memcmp(RomHeaderGameTitle, gSapphireTitleAndCode, 15) == TRUE) + else if (CheckSameString(RomHeaderGameTitle, sSapphireTitleAndCode, ROM_GAME_TITLE_LEN) == TRUE) { - if (shouldUpdate == 0) - return SAPPHIRE_NONEED; + if (shouldUpdate == FALSE) + { + return NO_UPDATE_SAPPHIRE; + } else { gGameVersion = VERSION_SAPPHIRE; - return SAPPHIRE_UPDATABLE; + return UPDATE_SAPPHIRE; } } } return INVALID; } -s32 validate_rom_header(void) +static s32 ValidateRomHeader(void) { - if (*RomHeaderMakerCode == '0' && *(RomHeaderMakerCode + 1) == '1' && *RomHeaderMagic == 0x96) - return validate_rom_header_internal(); + if (RomHeaderMakerCode[0] == '0' && RomHeaderMakerCode[1] == '1' && *RomHeaderMagic == ROM_HEADER_MAGIC) + return ValidateGameVersion(); else return INVALID; } -void main_callback(u32 * state, void * unused1, void * unused2) +static void BerryFix(u32 * state, void * unused1, void * unused2) { u8 year; switch (*state) { - case MAINCB_INIT: - MessageBox_Display(MSG_WILL_NOW_UPDATE); - if (++gInitialWaitTimer >= 180) + case STATE_INIT: + // "The Berry Program Update will now begin..." + MessageBox_Display(MSG_WILL_NOW_UPDATE); + if (++sInitialWaitTimer >= 180) + { + sInitialWaitTimer = 0; + gUpdateSuccessful = 0; + switch (ValidateRomHeader()) { - gInitialWaitTimer = 0; - gUpdateSuccessful = 0; - switch (validate_rom_header()) - { - case SAPPHIRE_UPDATABLE: - case RUBY_UPDATABLE: // Should Update Ruby - ++(*state); // MAINCB_CHECK_RTC - break; - case INVALID: // Invalid header - *state = MAINCB_ERROR; - break; - case SAPPHIRE_NONEED: // Should not update Sapphire - case RUBY_NONEED: // Should not update Ruby - *state = MAINCB_NO_NEED_TO_FIX; - break; - } + case UPDATE_SAPPHIRE: + case UPDATE_RUBY: + ++(*state); // STATE_CHECK_RTC + break; + case INVALID: // Invalid header + *state = STATE_ERROR; + break; + case NO_UPDATE_SAPPHIRE: + case NO_UPDATE_RUBY: + *state = STATE_NO_NEED_TO_FIX; + break; } - break; - case MAINCB_CHECK_RTC: - if (!BerryFix_TryInitRtc()) - *state = MAINCB_ERROR; + } + break; + case STATE_CHECK_RTC: + if (!BerryFix_TryInitRtc()) + *state = STATE_ERROR; + else + ++(*state); // STATE_CHECK_FLASH + break; + case STATE_CHECK_FLASH: + if (BerryFix_IdentifyFlash() == TRUE) + ++(*state); // STATE_READ_SAVE + else + *state = STATE_ERROR; + break; + case STATE_READ_SAVE: + if (BerryFix_LoadSave(0) == SAVE_STATUS_OK) + ++(*state); // STATE_CHECK_TIME + else + *state = STATE_ERROR; + break; + case STATE_CHECK_TIME: + if (BerryFix_CalcTimeDifference(&year) == TRUE) + { + // Time difference is okay, only fix the date if + // the Berry Glitch hasn't happened yet (if year is 2000) + if (year == 0) + ++(*state); // STATE_FIX_DATE else - ++(*state); // MAINCB_CHECK_FLASH - break; - case MAINCB_CHECK_FLASH: - if (BerryFix_IdentifyFlash() == TRUE) - ++(*state); // MAINCB_READ_SAVE + *state = STATE_CHECK_PACIFIDLOG_TM; + } + else + { + // Time difference is incorrect, if the year is 2001 + // then the Berry Glitch is occurring. If the year is + // not 2001 then some error has occurred. + if (year != 1) + *state = STATE_ERROR_YEAR; else - *state = MAINCB_ERROR; - break; - case MAINCB_READ_SAVE: - if (BerryFix_LoadSave(0) == SAVE_STATUS_OK) - ++(*state); // MAINCB_CHECK_TIME - else - *state = MAINCB_ERROR; - break; - case MAINCB_CHECK_TIME: - if (BerryFix_CalcTimeDifference(&year) == TRUE) - { - if (year == 0) - ++(*state); // MAINCB_FIX_DATE - else - *state = MAINCB_CHECK_PACIFIDLOG_TM; - } - else - { - if (year != 1) - *state = MAINCB_YEAR_MAKES_NO_SENSE; - else - ++(*state); // MAINCB_FIX_DATE - } - break; - case MAINCB_FIX_DATE: - BerryFix_SetDate(); + ++(*state); // STATE_FIX_DATE + } + break; + case STATE_FIX_DATE: + // Set the clock forward to fix the Berry Glitch + // If the date is late enough that it is no + // longer affected then this does nothing. + BerryFix_TryFixDate(); + gUpdateSuccessful |= 1; + *state = STATE_CHECK_PACIFIDLOG_TM; + break; + case STATE_CHECK_PACIFIDLOG_TM: + if (BerryFix_IsPacifidlogTMCorrect() == TRUE) + *state = STATE_FINISHED; + else + *state = STATE_FIX_PACIFIDLOG_TM; + break; + case STATE_FIX_PACIFIDLOG_TM: + // "Updating. the Berry Program. Please wait..." + MessageBox_Display(MSG_UPDATING); + if (BerryFix_ResetPacifidlogTM() == TRUE) + { gUpdateSuccessful |= 1; - *state = MAINCB_CHECK_PACIFIDLOG_TM; - break; - case MAINCB_CHECK_PACIFIDLOG_TM: - if (BerryFix_ShouldResetPacifidlogTM() == TRUE) - *state = MAINCB_FINISHED; - else - *state = MAINCB_FIX_PACIFIDLOG_TM; - break; - case MAINCB_FIX_PACIFIDLOG_TM: - MessageBox_Display(MSG_UPDATING); - if (BerryFix_ResetPacifidlogTM() == TRUE) - { - gUpdateSuccessful |= 1; - *state = MAINCB_FINISHED; - } - else - *state = MAINCB_ERROR; - break; - case MAINCB_FINISHED: - if (gUpdateSuccessful == 0) - *state = MAINCB_NO_NEED_TO_FIX; - else - MessageBox_Display(MSG_HAS_BEEN_UPDATED); - break; - case MAINCB_NO_NEED_TO_FIX: - MessageBox_Display(MSG_NO_NEED_TO_UPDATE); - break; - case MAINCB_YEAR_MAKES_NO_SENSE: - MessageBox_Display(MSG_UNABLE_TO_UPDATE); - break; - case MAINCB_ERROR: - MessageBox_Display(MSG_UNABLE_TO_UPDATE); - break; + *state = STATE_FINISHED; + } + else + { + *state = STATE_ERROR; + } + break; + // The below 4 cases are all the possible end states + // The Berry Fix Program will remain in these states until + // the player turns off the GBA. + case STATE_FINISHED: + if (gUpdateSuccessful == 0) + *state = STATE_NO_NEED_TO_FIX; + else // "Your Berry Program has been updated" + MessageBox_Display(MSG_HAS_BEEN_UPDATED); + break; + case STATE_NO_NEED_TO_FIX: + // "There is no need to update your Berry Program" + MessageBox_Display(MSG_NO_NEED_TO_UPDATE); + break; + case STATE_ERROR_YEAR: + // "Unable to update the Berry Program" + MessageBox_Display(MSG_UNABLE_TO_UPDATE); + break; + case STATE_ERROR: + // "Unable to update the Berry Program" + MessageBox_Display(MSG_UNABLE_TO_UPDATE); + break; } } -void DBG_LoadDigitsPal(void) +static void Debug_LoadDigitsPal(void) { s32 i; const u16 * src; vu16 * dest = (vu16 *)BG_PLTT + 1; - DmaFill16(3, RGB(31, 31, 31), (vu16 *)BG_PLTT, BG_PLTT_SIZE); + DmaFill16(3, RGB_WHITE, (vu16 *)BG_PLTT, BG_PLTT_SIZE); src = sDebugPals; for (i = 0; i < 4; i++) { @@ -283,9 +339,10 @@ void DBG_LoadDigitsPal(void) } } -void DBG_LoadDigits(void) +// Unused +static void Debug_LoadDigits(void) { DmaFill16(3, 0x1111, (void *)VRAM + 0x8420, 0x1800); DmaCopy32(3, sDebugDigitsGfx, (void *)VRAM + 0x8600, 0x200); - DBG_LoadDigitsPal(); -} + Debug_LoadDigitsPal(); +} \ No newline at end of file diff --git a/payload/src/rtc.c b/payload/src/rtc.c index 7f2571b..ea52fed 100644 --- a/payload/src/rtc.c +++ b/payload/src/rtc.c @@ -347,13 +347,15 @@ static bool32 RtcNeedsLeapDayIncrement(struct SiiRtcInfo * rtc) if (ConvertBcdToBinary(rtc->year) == 1) return TRUE; - // After 2001 just set clock forward 365 days + // After 2001 (shouldn't occur) return FALSE; } -void BerryFix_SetDate(void) +void BerryFix_TryFixDate(void) { RtcGetRawInfo(&sRtcInfoWork); + + // If the year is anything but 2000 or 2001 then the Berry Glitch has already passed if (ConvertBcdToBinary(sRtcInfoWork.year) == 0 || ConvertBcdToBinary(sRtcInfoWork.year) == 1) { if (ConvertBcdToBinary(sRtcInfoWork.year) == 1) @@ -367,7 +369,7 @@ void BerryFix_SetDate(void) } else { - // Berry Glitch hasn't begun yet (or was already passed) + // Year is 2000, the Berry Glitch hasn't begun yet // Set the date forward 365/366 days to avoid the glitch if (RtcNeedsLeapDayIncrement(&sRtcInfoWork) == TRUE) { From de7b85fd5639efe257bc32b6508d005d8253164b Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 15 Jan 2022 15:07:29 -0500 Subject: [PATCH 12/12] Add missing EOF newlines --- payload/src/main.c | 2 +- payload/src/rtc.c | 2 +- payload/src/siirtc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/payload/src/main.c b/payload/src/main.c index a2b3ef8..0a017e0 100644 --- a/payload/src/main.c +++ b/payload/src/main.c @@ -345,4 +345,4 @@ static void Debug_LoadDigits(void) DmaFill16(3, 0x1111, (void *)VRAM + 0x8420, 0x1800); DmaCopy32(3, sDebugDigitsGfx, (void *)VRAM + 0x8600, 0x200); Debug_LoadDigitsPal(); -} \ No newline at end of file +} diff --git a/payload/src/rtc.c b/payload/src/rtc.c index ea52fed..2b76927 100644 --- a/payload/src/rtc.c +++ b/payload/src/rtc.c @@ -383,4 +383,4 @@ void BerryFix_TryFixDate(void) RtcSetDateTime(&sRtcInfoWork); } } -} \ No newline at end of file +} diff --git a/payload/src/siirtc.c b/payload/src/siirtc.c index 5b05d99..9151abc 100644 --- a/payload/src/siirtc.c +++ b/payload/src/siirtc.c @@ -455,4 +455,4 @@ static void EnableGpioPortRead() static void DisableGpioPortRead() { GPIO_PORT_READ_ENABLE = FALSE; -} \ No newline at end of file +}