2019-09-03 20:33:11 +01:00
# include "gba/gba.h"
# include "gba/flash_internal.h"
# include "constants/vars.h"
# include "global.h"
# include "main.h"
# include "flash.h"
# include "rtc.h"
struct SaveBlockChunk
{
u8 * data ;
u16 size ;
} ;
u8 WriteSaveBlockChunks ( u16 a0 , const struct SaveBlockChunk * a1 ) ;
u8 WriteSingleChunk ( u16 a0 , const struct SaveBlockChunk * a1 ) ;
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 ) ;
u16 CalculateChecksum ( const void * , u16 ) ;
u16 gFirstSaveSector ;
u32 gPrevSaveCounter ;
u16 gLastKnownGoodSector ;
u32 gDamagedSaveSectors ;
u32 gSaveCounter ;
struct SaveSector * gFastSaveSection ;
u16 gCurSaveChunk ;
bool32 gFlashIdentIsValid ;
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 , \
min ( sizeof ( structure ) - chunkNum * SECTOR_DATA_SIZE , SECTOR_DATA_SIZE ) \
} \
static const struct SaveBlockChunk sSaveBlockChunks [ ] =
{
SAVEBLOCK_CHUNK ( gSaveBlock2 , 0 ) ,
SAVEBLOCK_CHUNK ( gSaveBlock1 , 0 ) ,
SAVEBLOCK_CHUNK ( gSaveBlock1 , 1 ) ,
SAVEBLOCK_CHUNK ( gSaveBlock1 , 2 ) ,
SAVEBLOCK_CHUNK ( gSaveBlock1 , 3 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 0 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 1 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 2 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 3 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 4 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 5 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 6 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 7 ) ,
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 " ) ;
bool32 flash_maincb_ident_is_valid ( void )
{
gFlashIdentIsValid = TRUE ;
if ( ! IdentifyFlash ( ) )
{
SetFlashTimerIntr ( 0 , & ( ( IntrFunc * ) gIntrFuncPointers ) [ 9 ] ) ;
return TRUE ;
}
gFlashIdentIsValid = FALSE ;
return FALSE ;
}
void Call_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 )
{
return WriteSaveBlockChunks ( a0 , a1 ) ;
}
u8 Call_TryReadAllSaveSectorsCurrentSlot ( u16 a0 , const struct SaveBlockChunk * a1 )
{
return TryReadAllSaveSectorsCurrentSlot ( a0 , a1 ) ;
}
u32 * GetDamagedSaveSectorsPtr ( void )
{
return & gDamagedSaveSectors ;
}
s32 flash_write_save_block_chunks ( u8 a0 )
{
u8 i ;
switch ( a0 )
{
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 ;
}
return 0 ;
}
u8 flash_write_save_block_chunks_check_damage ( u8 a0 )
{
flash_write_save_block_chunks ( a0 ) ;
if ( * GetDamagedSaveSectorsPtr ( ) = = 0 )
return 1 ;
return 0xFF ;
}
u8 flash_maincb_read_save ( u32 unused )
{
return Call_TryReadAllSaveSectorsCurrentSlot ( 0xFFFF , sSaveBlockChunks ) ;
}
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 , 0x200 ) ;
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 ;
}
}
void Save_EraseAllData ( void )
{
u16 i ;
for ( i = 0 ; i < 32 ; i + + )
EraseFlashSector ( i ) ;
}
void Save_ResetSaveCounters ( void )
{
gSaveCounter = 0 ;
gFirstSaveSector = 0 ;
gDamagedSaveSectors = 0 ;
}
bool32 SetSectorDamagedStatus ( u8 op , u8 sectorNum )
{
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 ;
}
return retVal ;
}
u8 WriteSaveBlockChunks ( u16 chunkId , const struct SaveBlockChunk * chunks )
{
u32 retVal ;
u16 i ;
gFastSaveSection = eSaveSection ;
if ( chunkId ! = 0xFFFF ) // write single chunk
{
retVal = WriteSingleChunk ( chunkId , chunks ) ;
}
else // write all chunks
{
gLastKnownGoodSector = gFirstSaveSector ;
gPrevSaveCounter = gSaveCounter ;
gFirstSaveSector + + ;
gFirstSaveSector % = NUM_SECTORS_PER_SAVE_SLOT ;
gSaveCounter + + ;
retVal = SAVE_STATUS_OK ;
for ( i = 0 ; i < NUM_SECTORS_PER_SAVE_SLOT ; i + + )
WriteSingleChunk ( i , chunks ) ;
// Check for any bad sectors
if ( gDamagedSaveSectors ! = 0 ) // skip the damaged sector.
{
retVal = SAVE_STATUS_ERROR ;
gFirstSaveSector = gLastKnownGoodSector ;
gSaveCounter = gPrevSaveCounter ;
}
}
return retVal ;
}
u8 WriteSingleChunk ( u16 chunkId , const struct SaveBlockChunk * chunks )
{
u16 i ;
u16 sectorNum ;
u8 * chunkData ;
u16 chunkSize ;
// select sector number
sectorNum = chunkId + gFirstSaveSector ;
sectorNum % = NUM_SECTORS_PER_SAVE_SLOT ;
// select save slot
sectorNum + = NUM_SECTORS_PER_SAVE_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 ;
gFastSaveSection - > id = chunkId ;
gFastSaveSection - > signature = FILE_SIGNATURE ;
gFastSaveSection - > counter = gSaveCounter ;
for ( i = 0 ; i < chunkSize ; i + + )
gFastSaveSection - > data [ i ] = chunkData [ i ] ;
gFastSaveSection - > checksum = CalculateChecksum ( chunkData , chunkSize ) ;
return TryWriteSector ( sectorNum , gFastSaveSection - > data ) ;
}
u8 HandleWriteSectorNBytes ( u8 sectorNum , u8 * data , u16 size )
{
u16 i ;
struct SaveSector * section = eSaveSection ;
for ( i = 0 ; i < sizeof ( struct SaveSector ) ; i + + )
( ( char * ) section ) [ i ] = 0 ;
section - > signature = FILE_SIGNATURE ;
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.
return TryWriteSector ( sectorNum , section - > data ) ;
}
u8 TryWriteSector ( u8 sectorNum , u8 * data )
{
2020-09-09 00:44:33 +01:00
if ( ProgramFlashSectorAndVerify ( sectorNum , data ) ) // is damaged?
2019-09-03 20:33:11 +01:00
{
SetSectorDamagedStatus ( SECTOR_DAMAGED , sectorNum ) ; // set damaged sector bits.
return SAVE_STATUS_ERROR ;
}
else
{
SetSectorDamagedStatus ( SECTOR_OK , sectorNum ) ; // unset damaged sector bits. it's safe now.
return SAVE_STATUS_OK ;
}
}
u32 RestoreSaveBackupVarsAndIncrement ( const struct SaveBlockChunk * chunk ) // chunk is unused
{
gFastSaveSection = eSaveSection ;
gLastKnownGoodSector = gFirstSaveSector ;
gPrevSaveCounter = gSaveCounter ;
gFirstSaveSector + + ;
gFirstSaveSector % = NUM_SECTORS_PER_SAVE_SLOT ;
gSaveCounter + + ;
gCurSaveChunk = 0 ;
gDamagedSaveSectors = 0 ;
return 0 ;
}
u32 RestoreSaveBackupVars ( const struct SaveBlockChunk * chunk )
{
gFastSaveSection = eSaveSection ;
gLastKnownGoodSector = gFirstSaveSector ;
gPrevSaveCounter = gSaveCounter ;
gCurSaveChunk = 0 ;
gDamagedSaveSectors = 0 ;
return 0 ;
}
u8 WriteSingleChunkAndIncrement ( u16 a1 , const struct SaveBlockChunk * chunk )
{
u8 retVal ;
if ( gCurSaveChunk < a1 - 1 )
{
retVal = SAVE_STATUS_OK ;
WriteSingleChunk ( gCurSaveChunk , chunk ) ;
gCurSaveChunk + + ;
if ( gDamagedSaveSectors )
{
retVal = SAVE_STATUS_ERROR ;
gFirstSaveSector = gLastKnownGoodSector ;
gSaveCounter = gPrevSaveCounter ;
}
}
else
{
retVal = SAVE_STATUS_ERROR ;
}
return retVal ;
}
u8 ErasePreviousChunk ( u16 a1 , const struct SaveBlockChunk * chunk )
{
u8 retVal = SAVE_STATUS_OK ;
EraseCurrentChunk ( a1 - 1 , chunk ) ;
if ( gDamagedSaveSectors )
{
retVal = SAVE_STATUS_ERROR ;
gFirstSaveSector = gLastKnownGoodSector ;
gSaveCounter = gPrevSaveCounter ;
}
return retVal ;
}
u8 EraseCurrentChunk ( u16 chunkId , const struct SaveBlockChunk * chunks )
{
u16 i ;
u16 sector ;
u8 * data ;
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 ) ;
data = chunks [ chunkId ] . data ;
size = chunks [ chunkId ] . size ;
// clear temp save section.
for ( i = 0 ; i < sizeof ( struct SaveSector ) ; i + + )
( ( char * ) gFastSaveSection ) [ i ] = 0 ;
gFastSaveSection - > id = chunkId ;
gFastSaveSection - > signature = FILE_SIGNATURE ;
gFastSaveSection - > counter = gSaveCounter ;
// set temp section's data.
for ( i = 0 ; i < size ; i + + )
gFastSaveSection - > data [ i ] = data [ i ] ;
// calculate checksum.
gFastSaveSection - > checksum = CalculateChecksum ( data , size ) ;
EraseFlashSector ( sector ) ;
status = SAVE_STATUS_OK ;
for ( i = 0 ; i < sizeof ( struct UnkSaveSection ) ; i + + )
{
if ( ProgramFlashByte ( sector , i , gFastSaveSection - > data [ i ] ) )
{
status = SAVE_STATUS_ERROR ;
break ;
}
}
if ( status = = SAVE_STATUS_ERROR )
{
SetSectorDamagedStatus ( SECTOR_DAMAGED , sector ) ;
return SAVE_STATUS_ERROR ;
}
else
{
status = SAVE_STATUS_OK ;
for ( i = 0 ; i < 7 ; i + + )
{
if ( ProgramFlashByte ( sector , 0xFF9 + i , ( ( u8 * ) gFastSaveSection ) [ 0xFF9 + i ] ) )
{
status = SAVE_STATUS_ERROR ;
break ;
}
}
if ( status = = SAVE_STATUS_ERROR )
{
SetSectorDamagedStatus ( SECTOR_DAMAGED , sector ) ;
return SAVE_STATUS_ERROR ;
}
else
{
SetSectorDamagedStatus ( SECTOR_OK , sector ) ;
return SAVE_STATUS_OK ;
}
}
}
u8 WriteSomeFlashByteToPrevSector ( u16 a1 , const struct SaveBlockChunk * chunk )
{
u16 sector ;
// 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 ) ] ) )
{
// sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
SetSectorDamagedStatus ( SECTOR_DAMAGED , sector ) ;
gFirstSaveSector = gLastKnownGoodSector ;
gSaveCounter = gPrevSaveCounter ;
return SAVE_STATUS_ERROR ;
}
else
{
SetSectorDamagedStatus ( SECTOR_OK , sector ) ;
return SAVE_STATUS_OK ;
}
}
u8 WriteSomeFlashByte0x25ToPrevSector ( u16 a1 , const struct SaveBlockChunk * chunk )
{
u16 sector ;
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 ) )
{
// sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
SetSectorDamagedStatus ( SECTOR_DAMAGED , sector ) ;
gFirstSaveSector = gLastKnownGoodSector ;
gSaveCounter = gPrevSaveCounter ;
return SAVE_STATUS_ERROR ;
}
else
{
SetSectorDamagedStatus ( SECTOR_OK , sector ) ;
return SAVE_STATUS_OK ;
}
}
u8 TryReadAllSaveSectorsCurrentSlot ( u16 a1 , const struct SaveBlockChunk * chunk )
{
u8 retVal ;
gFastSaveSection = eSaveSection ;
if ( a1 ! = 0xFFFF )
{
retVal = SAVE_STATUS_ERROR ;
}
else
{
retVal = GetSaveValidStatus ( chunk ) ;
ReadAllSaveSectorsCurrentSlot ( 0xFFFF , chunk ) ;
}
return retVal ;
}
u8 ReadAllSaveSectorsCurrentSlot ( u16 a1 , const struct SaveBlockChunk * chunks )
{
u16 i ;
u16 checksum ;
u16 sector = NUM_SECTORS_PER_SAVE_SLOT * ( gSaveCounter % 2 ) ;
u16 id ;
for ( i = 0 ; i < NUM_SECTORS_PER_SAVE_SLOT ; i + + )
{
DoReadFlashWholeSection ( i + sector , gFastSaveSection ) ;
id = gFastSaveSection - > id ;
if ( id = = 0 )
gFirstSaveSector = i ;
checksum = CalculateChecksum ( gFastSaveSection - > data , chunks [ id ] . size ) ;
if ( gFastSaveSection - > signature = = FILE_SIGNATURE
& & gFastSaveSection - > checksum = = checksum )
{
u16 j ;
for ( j = 0 ; j < chunks [ id ] . size ; j + + )
chunks [ id ] . data [ j ] = gFastSaveSection - > data [ j ] ;
}
}
return 1 ;
}
u8 GetSaveValidStatus ( const struct SaveBlockChunk * chunks )
{
u16 sector ;
bool8 signatureValid ;
u16 checksum ;
u32 slot1saveCounter = 0 ;
u32 slot2saveCounter = 0 ;
u8 slot1Status ;
u8 slot2Status ;
u32 validSectors ;
const u32 ALL_SECTORS = ( 1 < < NUM_SECTORS_PER_SAVE_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 + + )
{
DoReadFlashWholeSection ( sector , gFastSaveSection ) ;
if ( gFastSaveSection - > signature = = FILE_SIGNATURE )
{
signatureValid = TRUE ;
checksum = CalculateChecksum ( gFastSaveSection - > data , chunks [ gFastSaveSection - > id ] . size ) ;
if ( gFastSaveSection - > checksum = = checksum )
{
slot1saveCounter = gFastSaveSection - > counter ;
validSectors | = 1 < < gFastSaveSection - > id ;
}
}
}
if ( signatureValid )
{
if ( validSectors = = ALL_SECTORS )
slot1Status = SAVE_STATUS_OK ;
else
slot1Status = SAVE_STATUS_ERROR ;
}
else
{
slot1Status = SAVE_STATUS_EMPTY ;
}
// check save slot 2.
validSectors = 0 ;
signatureValid = FALSE ;
for ( sector = 0 ; sector < NUM_SECTORS_PER_SAVE_SLOT ; sector + + )
{
DoReadFlashWholeSection ( NUM_SECTORS_PER_SAVE_SLOT + sector , gFastSaveSection ) ;
if ( gFastSaveSection - > signature = = FILE_SIGNATURE )
{
signatureValid = TRUE ;
checksum = CalculateChecksum ( gFastSaveSection - > data , chunks [ gFastSaveSection - > id ] . size ) ;
if ( gFastSaveSection - > checksum = = checksum )
{
slot2saveCounter = gFastSaveSection - > counter ;
validSectors | = 1 < < gFastSaveSection - > id ;
}
}
}
if ( signatureValid )
{
if ( validSectors = = ALL_SECTORS )
slot2Status = SAVE_STATUS_OK ;
else
slot2Status = SAVE_STATUS_ERROR ;
}
else
{
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 ( ( unsigned ) ( slot1saveCounter + 1 ) < ( unsigned ) ( slot2saveCounter + 1 ) )
gSaveCounter = slot2saveCounter ;
else
gSaveCounter = slot1saveCounter ;
}
else
{
if ( slot1saveCounter < slot2saveCounter )
gSaveCounter = slot2saveCounter ;
else
gSaveCounter = slot1saveCounter ;
}
return SAVE_STATUS_OK ;
}
if ( slot1Status = = SAVE_STATUS_OK )
{
gSaveCounter = slot1saveCounter ;
if ( slot2Status = = SAVE_STATUS_ERROR )
return SAVE_STATUS_ERROR ;
else
return SAVE_STATUS_OK ;
}
if ( slot2Status = = SAVE_STATUS_OK )
{
gSaveCounter = slot2saveCounter ;
if ( slot1Status = = SAVE_STATUS_ERROR )
return SAVE_STATUS_ERROR ;
else
return SAVE_STATUS_OK ;
}
if ( slot1Status = = SAVE_STATUS_EMPTY & & slot2Status = = SAVE_STATUS_EMPTY )
{
gSaveCounter = 0 ;
gFirstSaveSector = 0 ;
return SAVE_STATUS_EMPTY ;
}
gSaveCounter = 0 ;
gFirstSaveSector = 0 ;
return 2 ;
}
u8 ReadSomeUnknownSectorAndVerify ( u8 sector , u8 * data , u16 size )
{
u16 i ;
struct SaveSector * section = eSaveSection ;
DoReadFlashWholeSection ( sector , section ) ;
if ( section - > signature = = FILE_SIGNATURE )
{
u16 checksum = CalculateChecksum ( section - > data , size ) ;
if ( section - > id = = checksum )
{
for ( i = 0 ; i < size ; i + + )
data [ i ] = section - > data [ i ] ;
return SAVE_STATUS_OK ;
}
else
{
return 2 ;
}
}
else
{
return SAVE_STATUS_EMPTY ;
}
}
u32 DoReadFlashWholeSection ( u8 sector , struct SaveSector * section )
{
ReadFlash ( sector , 0 , section - > data , sizeof ( struct SaveSector ) ) ;
return 1 ;
}
u16 CalculateChecksum ( const void * data , u16 size )
{
u16 i ;
u32 checksum = 0 ;
for ( i = 0 ; i < ( size / 4 ) ; i + + )
{
checksum + = * ( ( u32 * ) data ) ;
data + = sizeof ( u32 ) ;
}
return ( ( checksum > > 16 ) + checksum ) ;
}
void nullsub_0201182C ( )
{
}
void nullsub_02011830 ( )
{
}
void nullsub_02011834 ( )
{
}
u16 * get_var_addr ( u16 a0 )
{
if ( a0 < VARS_START )
return NULL ;
if ( a0 < VAR_SPECIAL_0 )
return & gSaveBlock1 . vars [ a0 - 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 ) ;
rtc_maincb_is_time_since_last_berry_update_positive ( & sp0 ) ;
if ( * data < = gRtcUTCTime . days )
return TRUE ;
else
return FALSE ;
}
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 ;
* get_var_addr ( VAR_PACIFIDLOG_TM_RECEIVED_DAY ) = 1 ;
if ( flash_write_save_block_chunks_check_damage ( 0 ) ! = TRUE )
return FALSE ;
return TRUE ;
}