#ifndef GUARD_LINK_H #define GUARD_LINK_H #define MAX_LINK_PLAYERS 4 #define MAX_RFU_PLAYERS 5 #define CMD_LENGTH 8 #define QUEUE_CAPACITY 50 #define BLOCK_BUFFER_SIZE 0x100 #define LINK_STAT_LOCAL_ID 0x00000003 #define LINK_STAT_PLAYER_COUNT 0x0000001C #define LINK_STAT_PLAYER_COUNT_SHIFT 2 #define LINK_STAT_MASTER 0x00000020 #define LINK_STAT_MASTER_SHIFT 5 #define LINK_STAT_CONN_ESTABLISHED 0x00000040 #define LINK_STAT_CONN_ESTABLISHED_SHIFT 6 #define LINK_STAT_RECEIVED_NOTHING 0x00000100 #define LINK_STAT_RECEIVED_NOTHING_SHIFT 8 #define LINK_STAT_ERRORS 0x0007F000 #define EXTRACT_PLAYER_COUNT(status) \ (((status) & LINK_STAT_PLAYER_COUNT) >> LINK_STAT_PLAYER_COUNT_SHIFT) #define EXTRACT_MASTER(status) \ (((status) >> LINK_STAT_MASTER_SHIFT) & 1) #define EXTRACT_CONN_ESTABLISHED(status) \ (((status) >> LINK_STAT_CONN_ESTABLISHED_SHIFT) & 1) #define EXTRACT_RECEIVED_NOTHING(status) \ (((status) >> LINK_STAT_RECEIVED_NOTHING_SHIFT) & 1) struct LinkStatus { u32 localId:2; u32 playerCount:3; u32 master:1; u32 connEstablished:1; u32 unused_7:1; u32 receivedNothing:1; u32 unused_9:7; u32 errors:7; }; #define MASTER_HANDSHAKE 0x8FFF #define SLAVE_HANDSHAKE 0xB9A0 #define SIO_MULTI_CNT ((volatile struct SioMultiCnt *)REG_ADDR_SIOCNT) enum { LINK_STATE_START0, LINK_STATE_START1, LINK_STATE_HANDSHAKE, LINK_STATE_INIT_TIMER, LINK_STATE_CONN_ESTABLISHED, }; enum { EXCHANGE_NOT_STARTED, EXCHANGE_COMPLETE, EXCHANGE_TIMED_OUT, EXCHANGE_IN_PROGRESS, EXCHANGE_STAT_4, EXCHANGE_STAT_5, EXCHANGE_STAT_6 }; enum { QUEUE_FULL_NONE, QUEUE_FULL_SEND, QUEUE_FULL_RECV, }; enum { LAG_NONE, LAG_MASTER, LAG_SLAVE, }; struct LinkPlayer { /* 0x00 */ u16 version; /* 0x02 */ u16 lp_field_2; /* 0x04 */ u32 trainerId; /* 0x08 */ u8 name[11]; /* 0x13 */ u8 gender; /* 0x14 */ u32 linkType; /* 0x18 */ u16 lp_field_18; /* 0x1A */ u16 language; }; struct LinkPlayerBlock { u8 magic1[16]; struct LinkPlayer linkPlayer; u8 magic2[16]; }; // circular queues struct SendQueue { u16 data[CMD_LENGTH][QUEUE_CAPACITY]; u8 pos; u8 count; }; struct RecvQueue { u16 data[MAX_LINK_PLAYERS][CMD_LENGTH][QUEUE_CAPACITY]; u8 pos; u8 count; }; struct Link { u8 isMaster; // 0: slave, 8: master u8 state; u8 localId; // local multi-player ID u8 playerCount; u16 tempRecvBuffer[4]; bool8 receivedNothing; s8 serialIntrCounter; bool8 handshakeAsMaster; u8 link_field_F; // error conditions bool8 hardwareError; // hardware reported an error bool8 badChecksum; // checksum didn't match between devices u8 queueFull; // send or recv queue out of space u8 lag; // connection is lagging u16 checksum; u8 sendCmdIndex; u8 recvCmdIndex; struct SendQueue sendQueue; struct RecvQueue recvQueue; }; struct BlockRequest { void * address; u32 size; }; extern const struct BlockRequest sBlockRequestLookupTable[5]; extern struct Link gLink; extern u16 gRecvCmds[MAX_LINK_PLAYERS][CMD_LENGTH]; extern u8 gBlockSendBuffer[BLOCK_BUFFER_SIZE]; // gBlockSendBuffer extern u8 gBlockSendBuffer[BLOCK_BUFFER_SIZE]; extern u16 gLinkType; extern u32 gLinkStatus; extern u16 gBlockRecvBuffer[MAX_RFU_PLAYERS][BLOCK_BUFFER_SIZE / 2]; extern u16 gSendCmd[CMD_LENGTH]; extern u8 gShouldAdvanceLinkState; extern struct LinkPlayer gLinkPlayers[]; extern u16 word_3002910[]; extern bool8 gReceivedRemoteLinkPlayers; extern bool8 gSerialIsRFU; void Task_DestroySelf(u8); void OpenLink(void); void CloseLink(void); u16 LinkMain2(const u16 *); void sub_8007B14(void); bool32 sub_8007B24(void); void ClearLinkCallback(void); void ClearLinkCallback_2(void); u8 GetLinkPlayerCount(void); void OpenLinkTimed(void); u8 GetLinkPlayerDataExchangeStatusTimed(int lower, int upper); bool8 IsLinkPlayerDataExchangeComplete(void); u32 GetLinkPlayerTrainerId(u8); void ResetLinkPlayers(void); void sub_8007E24(void); void sub_8007E4C(void); u8 GetMultiplayerId(void); u8 bitmask_all_link_players_but_self(void); bool8 SendBlock(u8, const void *, u16); u8 GetBlockReceivedStatus(void); void ResetBlockReceivedFlags(void); void ResetBlockReceivedFlag(u8); u8 GetLinkPlayerCount_2(void); bool8 IsLinkMaster(void); void CB2_LinkError(void); u8 GetSioMultiSI(void); bool8 IsLinkConnectionEstablished(void); void SetSuppressLinkErrorMessage(bool8); bool8 HasLinkErrorOccurred(void); void ResetSerial(void); u32 LinkMain1(u8 *, u16 *, u16[CMD_LENGTH][MAX_LINK_PLAYERS]); void LinkVSync(void); void Timer3Intr(void); void SerialCB(void); u8 GetLinkPlayerCount(void); void sub_800E0E8(void); bool8 sub_800A520(void); void sub_800DFB4(u8, u8); void sub_800ADF8(void); void sub_800B488(void); void sub_800A620(void); void sub_8011BD0(void); u8 sub_800ABAC(void); u8 sub_800ABBC(void); void sub_800AC34(void); void SetLinkDebugValues(u32 seed, u32 flags); void sub_800A418(void); void SetSuppressLinkErrorMessage(bool8 flag); void sub_800B524(struct LinkPlayer *linkPlayer); u8 sub_800B2E8(void); u8 sub_800B320(void); u8 sub_800B33C(void); extern u16 gUnknown_03003020[6]; extern u32 gUnknown_0300302C; extern struct LinkPlayerBlock gLocalLinkPlayerBlock; extern bool8 gLinkErrorOccurred; extern u32 gUnknown_03003070; extern bool8 gUnknown_03003078[4]; extern u8 gUnknown_0300307C[4]; extern u16 gLinkHeldKeys; extern u32 gLinkStatus; extern u8 gUnknown_030030E4; extern u8 gUnknown_030030E8; extern u8 gUnknown_030030EC[4]; extern u8 gUnknown_030030F0[4]; extern u16 gUnknown_030030F4; extern u8 gSuppressLinkErrorMessage; extern bool8 gSerialIsRFU; extern bool8 gUnknown_03003100; extern u8 gUnknown_03003120; extern struct LinkTestBGInfo gLinkTestBGInfo; extern void (*gLinkCallback)(void); extern bool8 gShouldAdvanceLinkState; extern u16 gLinkTestBlockChecksums[4]; extern u8 gBlockRequestType; extern u8 gUnknown_03003160; extern u8 gUnknown_03004130; #endif // GUARD_LINK_H