#ifndef GUARD_LINK_H #define GUARD_LINK_H #define MAX_LINK_PLAYERS 4 #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) #define MASTER_HANDSHAKE 0x8FFF #define SLAVE_HANDSHAKE 0xB9A0 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, }; 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[CMD_LENGTH][MAX_LINK_PLAYERS]; extern u8 gBlockSendBuffer[BLOCK_BUFFER_SIZE]; extern u16 gLinkType; extern u32 gLinkStatus; extern u16 gBlockRecvBuffer[MAX_LINK_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 gLinkVSyncDisabled; void Task_DestroySelf(u8); void OpenLink(void); void CloseLink(void); u16 LinkMain2(u16 *); void sub_8007B14(void); bool32 sub_8007B24(void); void ClearLinkCallback(void); void ClearLinkCallback_2(void); u8 GetLinkPlayerCount(void); void OpenLinkTimed(void); u8 GetLinkPlayerDataExchangeStatusTimed(void); 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, void *, u16); u8 GetBlockReceivedStatus(void); void ResetBlockReceivedFlags(void); void ResetBlockReceivedFlag(u8); void SetLinkDebugValues(u32, u32); 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); bool8 sub_8010500(void); void sub_800DFB4(u8, u8); void sub_800ADF8(void); void sub_800B488(void); void sub_8009734(void); void sub_800A620(void); void sub_8011BD0(void); u8 sub_800ABAC(void); u8 sub_800ABBC(void); void sub_800AC34(void); #endif // GUARD_LINK_H