diff options
Diffstat (limited to 'src/ereader_helpers.c')
-rw-r--r-- | src/ereader_helpers.c | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/src/ereader_helpers.c b/src/ereader_helpers.c new file mode 100644 index 000000000..2a9b9ea71 --- /dev/null +++ b/src/ereader_helpers.c @@ -0,0 +1,397 @@ +#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)) + gUnknown_3003F84 = 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 + { + gUnknown_3003F84 = 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)) + gUnknown_3003F84 = 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 + { + gUnknown_3003F84 = 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; + gUnknown_3003F84 = 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 (gUnknown_3003F84 == 2) + { + sSendRecvMgr.field_04 = 2; + sSendRecvMgr.state = 6; + } + break; + case 2: + OpenSerial32(); + SetUpTransferManager(size, data, recvBuffer); + sSendRecvMgr.state = 3; + // fallthrough + case 3: + if (gUnknown_3003F84 == 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)); +} |