summaryrefslogtreecommitdiff
path: root/src/ereader_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ereader_helpers.c')
-rw-r--r--src/ereader_helpers.c397
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));
+}