#include "global.h" #include "link.h" #include "unk_815c27c.h" enum { EREADER_XFR_STATE_INIT, EREADER_XFR_STATE_HANDSHAKE, EREADER_XFR_STATE_START, EREADER_XFR_STATE_TRANSFER, }; struct SendRecvMgr { u8 sendOrRecv; u8 state; u8 field_02; u8 field_03; u8 field_04; u32 * dataptr; int cursor; int size; u32 checksum; }; static bool16 DetermineSendRecvState(u8); static void SetUpTransferManager(size_t, const void *, void *); static void StartTm3(void); static void EnableSio(void); static void DisableTm3(void); static void GetKeyInput(void); static struct SendRecvMgr sSendRecvMgr; static u16 sJoyNewOrRepeated; static u16 sJoyNew; static u16 sSendRecvStatus; static u16 sCounter1; static u32 sCounter2; static u16 sSavedIme; static u16 sSavedIe; static u16 sSavedTm3Cnt; static u16 sSavedSioCnt; static u16 sSavedSioCnt; static u16 sSavedRCnt; int EReader_Send(size_t r6, const void * r5) { int result; EReaderHelper_SaveRegsState(); while (1) { GetKeyInput(); if (TEST_BUTTON(sJoyNew, B_BUTTON)) gShouldAdvanceLinkState = 2; sSendRecvStatus = EReaderHandleTransfer(1, r6, r5, NULL); if ((sSendRecvStatus & 0x13) == 0x10) { result = 0; break; } else if (sSendRecvStatus & 8) { result = 1; break; } else if (sSendRecvStatus & 4) { result = 2; break; } else { gShouldAdvanceLinkState = 0; VBlankIntrWait(); } } CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); EReaderHelper_RestoreRegsState(); return result; } int EReader_Recv(void * r5) { int result; EReaderHelper_SaveRegsState(); while (1) { GetKeyInput(); if (TEST_BUTTON(sJoyNew, B_BUTTON)) gShouldAdvanceLinkState = 2; sSendRecvStatus = EReaderHandleTransfer(0, 0, NULL, r5); if ((sSendRecvStatus & 0x13) == 0x10) { result = 0; break; } else if (sSendRecvStatus & 8) { result = 1; break; } else if (sSendRecvStatus & 4) { result = 2; break; } else { gShouldAdvanceLinkState = 0; VBlankIntrWait(); } } CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); EReaderHelper_RestoreRegsState(); return result; } static void CloseSerial(void) { REG_IME = 0; REG_IE &= ~(INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); REG_IME = 1; REG_SIOCNT = 0; REG_TM3CNT_H = 0; REG_IF = INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL; } static void OpenSerialMulti(void) { REG_IME = 0; REG_IE &= ~(INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); REG_IME = 1; REG_RCNT = 0; REG_SIOCNT = SIO_MULTI_MODE; REG_SIOCNT |= SIO_INTR_ENABLE | SIO_115200_BPS; REG_IME = 0; REG_IE |= INTR_FLAG_SERIAL; REG_IME = 1; if (sSendRecvMgr.state == 0) CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); } static void OpenSerial32(void) { REG_RCNT = 0; REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE; REG_SIOCNT |= SIO_MULTI_SD; gShouldAdvanceLinkState = 0; sCounter1 = 0; sCounter2 = 0; } u16 EReaderHandleTransfer(u8 mode, size_t size, const void * data, void * recvBuffer) { switch (sSendRecvMgr.state) { case 0: OpenSerialMulti(); sSendRecvMgr.field_02 = 1; sSendRecvMgr.state = 1; break; case 1: if (DetermineSendRecvState(mode)) EnableSio(); if (gShouldAdvanceLinkState == 2) { sSendRecvMgr.field_04 = 2; sSendRecvMgr.state = 6; } break; case 2: OpenSerial32(); SetUpTransferManager(size, data, recvBuffer); sSendRecvMgr.state = 3; // fallthrough case 3: if (gShouldAdvanceLinkState == 2) { sSendRecvMgr.field_04 = 2; sSendRecvMgr.state = 6; } else { sCounter1++; sCounter2++; if (sSendRecvMgr.sendOrRecv == 0 && sCounter2 > 60) { sSendRecvMgr.field_04 = 1; sSendRecvMgr.state = 6; } if (sSendRecvMgr.field_02 != 2) { if (sSendRecvMgr.sendOrRecv != 0 && sCounter1 > 2) { EnableSio(); sSendRecvMgr.field_02 = 2; } else { EnableSio(); sSendRecvMgr.field_02 = 2; } } } break; case 4: OpenSerialMulti(); sSendRecvMgr.state = 5; break; case 5: if (sSendRecvMgr.sendOrRecv == 1 && sCounter1 > 2) EnableSio(); if (++sCounter1 > 60) { sSendRecvMgr.field_04 = 1; sSendRecvMgr.state = 6; } break; case 6: if (sSendRecvMgr.field_02 != 0) { CloseSerial(); sSendRecvMgr.field_02 = 0; } break; } return sSendRecvMgr.field_02 | (sSendRecvMgr.field_04 << 2) | (sSendRecvMgr.field_03 << 4); } static bool16 DetermineSendRecvState(u8 mode) { bool16 resp; if ((*(vu32 *)REG_ADDR_SIOCNT & (SIO_MULTI_SI | SIO_MULTI_SD)) == SIO_MULTI_SD && mode) resp = sSendRecvMgr.sendOrRecv = TRUE; else resp = sSendRecvMgr.sendOrRecv = FALSE; return resp; } static void SetUpTransferManager(size_t size, const void * data, void * recvBuffer) { if (sSendRecvMgr.sendOrRecv) { REG_SIOCNT |= SIO_38400_BPS; sSendRecvMgr.dataptr = (void *)data; REG_SIODATA32 = size; sSendRecvMgr.size = size / 4 + 1; StartTm3(); } else { REG_SIOCNT |= SIO_9600_BPS; sSendRecvMgr.dataptr = recvBuffer; } } static void StartTm3(void) { REG_TM3CNT_L = -601; REG_TM3CNT_H = TIMER_INTR_ENABLE; REG_IME = 0; REG_IE |= INTR_FLAG_TIMER3; REG_IME = 1; } void EReaderHelper_Timer3Callback(void) { DisableTm3(); EnableSio(); } void EReaderHelper_SerialCallback(void) { u16 recv[4]; u16 i; u16 cnt1; u16 cnt2; u32 recv32; switch (sSendRecvMgr.state) { case 1: REG_SIOMLT_SEND = 0xCCD0; *(u64 *)recv = REG_SIOMLT_RECV; for (i = 0, cnt1 = 0, cnt2 = 0; i < 4; i++) { if (recv[i] == 0xCCD0) cnt1++; else if (recv[i] != 0xFFFF) cnt2++; } if (cnt1 == 2 && cnt2 == 0) sSendRecvMgr.state = 2; break; case 3: recv32 = REG_SIODATA32; if (sSendRecvMgr.cursor == 0 && sSendRecvMgr.sendOrRecv == 0) sSendRecvMgr.size = recv32 / 4 + 1; if (sSendRecvMgr.sendOrRecv == 1) { if (sSendRecvMgr.cursor < sSendRecvMgr.size) { REG_SIODATA32 = sSendRecvMgr.dataptr[sSendRecvMgr.cursor]; sSendRecvMgr.checksum += sSendRecvMgr.dataptr[sSendRecvMgr.cursor]; } else REG_SIODATA32 = sSendRecvMgr.checksum; } else { if (sSendRecvMgr.cursor > 0 && sSendRecvMgr.cursor < sSendRecvMgr.size + 1) { sSendRecvMgr.dataptr[sSendRecvMgr.cursor - 1] = recv32; sSendRecvMgr.checksum += recv32; } else if (sSendRecvMgr.cursor != 0) { if (sSendRecvMgr.checksum == recv32) sSendRecvMgr.field_03 = 1; else sSendRecvMgr.field_03 = 2; } sCounter2 = 0; } sSendRecvMgr.cursor++; if (sSendRecvMgr.cursor < sSendRecvMgr.size + 2) { if (sSendRecvMgr.sendOrRecv != 0) REG_TM3CNT_H |= TIMER_ENABLE; else EnableSio(); } else { sSendRecvMgr.state = 4; sCounter1 = 0; } break; case 5: if (sSendRecvMgr.sendOrRecv == 0) REG_SIODATA8 = sSendRecvMgr.field_03; *(vu64 *)recv = REG_SIOMLT_RECV; if (recv[1] == 1 || recv[1] == 2) { if (sSendRecvMgr.sendOrRecv == 1) sSendRecvMgr.field_03 = recv[1]; sSendRecvMgr.state = 6; } break; } } static void EnableSio(void) { REG_SIOCNT |= SIO_ENABLE; } static void DisableTm3(void) { REG_TM3CNT_H &= ~TIMER_ENABLE; REG_TM3CNT_L = -601; } static void GetKeyInput(void) { u16 rawKeys = REG_KEYINPUT ^ 0x3FF; sJoyNew = rawKeys & ~sJoyNewOrRepeated; sJoyNewOrRepeated = rawKeys; } void EReaderHelper_SaveRegsState(void) { sSavedIme = REG_IME; sSavedIe = REG_IE; sSavedTm3Cnt = REG_TM3CNT_H; sSavedSioCnt = REG_SIOCNT; sSavedRCnt = REG_RCNT; } void EReaderHelper_RestoreRegsState(void) { REG_IME = sSavedIme; REG_IE = sSavedIe; REG_TM3CNT_H = sSavedTm3Cnt; REG_SIOCNT = sSavedSioCnt; REG_RCNT = sSavedRCnt; } void EReaderHelper_ClearsSendRecvMgr(void) { CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); }