#ifndef CARD_H
#define CARD_H
#include <nds.h>
#include <types.h>
#include <os_card.h>
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------------------------
-- macros
-----------------------------------------------------------------------------*/
#define MAX_CARD_RETRIES 10
#define LPKM_BACKUP_TYPE_4MBIT_FLASH 0xFF1302
/*-----------------------------------------------------------------------------
-- type definitions
-----------------------------------------------------------------------------*/
typedef void (*CardCallbackFn)(void*);
/*-----------------------------------------------------------------------------
-- enums
-----------------------------------------------------------------------------*/
typedef enum CardResult {
RESULT_SUCCESS = 0,
RESULT_FAIL = 1,
RESULT_INVALID_PARAM = 2,
RESULT_UNSUPPORTED = 3,
RESULT_TIMEOUT = 4,
RESULT_ERROR = 5,
RESULT_NO_RESPONSE = 6,
RESULT_CANCELED = 7
} CardResult;
typedef enum CardRequest {
REQUEST_INIT = 0,
REQUEST_ACK = 1,
REQUEST_IDENTIFY = 2,
REQUEST_READ_ID = 3,
REQUEST_READ_ROM = 4,
REQUEST_WRITE_ROM = 5,
REQUEST_READ_BACKUP = 6,
REQUEST_WRITE_BACKUP = 7,
REQUEST_PROGRAM_BACKUP = 8,
REQUEST_VERIFY_BACKUP = 9,
REQUEST_ERASE_PAGE_BACKUP = 10,
REQUEST_ERASE_SECTOR_BACKUP = 11,
REQUEST_ERASE_CHIP_BACKUP = 12,
REQUEST_READ_STATUS = 13,
REQUEST_WRITE_STATUS = 14,
REQUEST_ERASE_SUBSECTOR_BACKUP = 15,
REQUEST_MAX = 16
} CardRequest;
typedef enum CardRequestMode {
REQUEST_MODE_RECV = 0,
REQUEST_MODE_SEND = 1,
REQUEST_MODE_SEND_VERIFY = 2,
REQUEST_MODE_SPECIAL = 3
} CardRequestMode;
/*-----------------------------------------------------------------------------
-- structs
-----------------------------------------------------------------------------*/
typedef struct RomRegion {
u32 offset;
u32 length;
} RomRegion;
/*-----------------------------------------------------------------------------
-- types
-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
-- inline Functions
-----------------------------------------------------------------------------*/
_INLINE bool ReadCardBackupHw(u32 src, void* dest, u32 size, CardCallbackFn cb, void* cb_arg, bool is_async)
{
return CARDi_RequestStreamCommand((u32)src, (u32)dest, size, cb, cb_arg, is_async, REQUEST_READ_BACKUP, 1, REQUEST_MODE_RECV);
}
/*
ReadSave args:
src: offset to start reading at in the save- 0 if you're reading from the top
dest: buffer to read into
size: read size
cb: callback function- this is the function that will be run if the save read completes successfully. use NULL if you don't need one.
cb_arg: callback function argument- ptr to the argument for the callback function. also NULL if unused.
*/
_INLINE bool ReadSave(u32 src, void* dest, u32 size, CardCallbackFn cb, void* cb_arg)
{
return ReadCardBackupHw(src, dest, size, cb, cb_arg, TRUE);
}
/*
to use:
bool g_save_read = FALSE;
void SetSavReadFlag()
{
save_read = TRUE;
}
const char* sav_src = "save_src.cpp";
void* save_buf = allocateBlockFromExpHeap(GRP_ID_SAV_BLK, BLK_LEN, TRUE, sav_src, SAV_BLK_LOAD_MK);
bool save_result = ReadSave(0 + block_address_you_use_if_any, save_buf, BLK_LEN, SetSavReadFlag, NULL);
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
_INLINE void WriteCardBackupHw(u32 dest, const void* src, u32 size, CardCallbackFn cb, void* cb_arg, bool is_async)
{
CARDi_RequestStreamCommand((u32)src, (u32)dest, size, cb, cb_arg, is_async, REQUEST_WRITE_BACKUP, MAX_CARD_RETRIES, REQUEST_MODE_SEND_VERIFY);
}
/*
WriteSave args:
dest: offset into the save to write
src: address in memory to start writing from
size: write size
cb: callback function- this is the function that will be run if the save read completes successfully. use NULL if you don't need one.
cb_arg: callback function argument- ptr to the argument for the callback function. also NULL if unused.
*/
_INLINE void WriteSave(u32 dest, const void* src, u32 size, CallbackFn cb, void* cb_arg)
{
WriteCardBackupHw(dest, src, size, cb, cb_arg, TRUE);
}
/*-----------------------------------------------------------------------------
-- function declarations
-----------------------------------------------------------------------------*/
bool CARD_IsEnabled();
void CARD_CheckEnabled();
void CARD_Enable(bool enable);
CardResult CARD_GetResultCode();
const u8* CARD_GetRomHeader();
void CARD_LockRom(u16 lock_id); // lock access to card rom - you call OS_GetLockID first to get the lock id to use here, lock_id is basically the owner of the current lock/unlock action
void CARD_UnlockRom(u16 lock_id); // once you unlock access, use the same os lock id
void CARD_LockBackup(u16 lock_id); // lock access to card backup - call OS_GetLockID first
void CARD_UnlockBackup(u16 lock_id);
bool CARDi_RequestStreamCommand(u32 src, u32 dst, u32 len, CallbackFn callback, void *arg, BOOL is_async, CardRequest req_type, int req_retry, CardRequestMode req_mode);
bool CARD_IdentifyBackup(u32 backup_type); // you CAN use this, but you don't have to. the type of backup is pre-identified by gamefreak.
u32 CARD_GetBackupSectorSize();
bool CARD_WaitBackupAsync();
bool CARD_TryWaitBackupAsync();
void CARD_CancelBackupAsync(); // kill the currently running async process for the card
void CARD_WaitRomAsync();
bool CARD_IsPulledOut();
#ifdef __cplusplus
} /* extern "C"*/
#endif
#endif // CARD_H
/*
full example of reading from a save:
bool g_save_read = FALSE;
void ReadInSavBlk(u32 read_size, void* data_dest, u32 read_offset)
{
s32 id = OS_GetLockID();
if(id == LOCK_ID_ERR)
{
assert_fail();
}
CARD_LockBackup((u16)id);
UnsetSavReadFlag();
ReadSave(read_offset, data_dest, read_size, SetSavReadFlag, NULL);
CARD_UnlockBackup((u16)id);
OS_ReleaseLockID((u16)id);
}
void SetSavReadFlag()
{
save_read = TRUE;
}
void UnsetSavReadFlag()
{
save_read = FALSE;
}
*/
// NOTE: you do not have to use a callback. this is just a demonstration of how to.
Comments