Document ereader_helpers.c

This commit is contained in:
PikalaxALT
2020-02-11 16:26:50 -05:00
parent 11af7a0751
commit 325c5b3f11
3 changed files with 113 additions and 79 deletions
+26 -1
View File
@@ -1,11 +1,36 @@
#ifndef GUARD_EREADER_HELPERS_H #ifndef GUARD_EREADER_HELPERS_H
#define GUARD_EREADER_HELPERS_H #define GUARD_EREADER_HELPERS_H
enum {
EREADER_XFR_STATE_INIT = 0,
EREADER_XFR_STATE_HANDSHAKE,
EREADER_XFR_STATE_START,
EREADER_XFR_STATE_TRANSFER,
EREADER_XFR_STATE_TRANSFER_DONE,
EREADER_XFR_STATE_CHECKSUM,
EREADER_XFR_STATE_DONE
};
#define EREADER_XFER_EXE 1
#define EREADER_XFER_CHK 2
#define EREADER_XFER_SHIFT 0
#define EREADER_XFER_MASK 3
#define EREADER_CANCEL_TIMEOUT 1
#define EREADER_CANCEL_KEY 2
#define EREADER_CANCEL_MASK 0xC
#define EREADER_CANCEL_SHIFT 2
#define EREADER_CHECKSUM_OK 1
#define EREADER_CHECKSUM_ERR 2
#define EREADER_CHECKSUM_MASK 0x30
#define EREADER_CHECKSUM_SHIFT 4
void EReaderHelper_SerialCallback(void); void EReaderHelper_SerialCallback(void);
void EReaderHelper_Timer3Callback(void); void EReaderHelper_Timer3Callback(void);
void EReaderHelper_SaveRegsState(void); void EReaderHelper_SaveRegsState(void);
void EReaderHelper_ClearsSendRecvMgr(void); void EReaderHelper_ClearsSendRecvMgr(void);
void EReaderHelper_RestoreRegsState(void); void EReaderHelper_RestoreRegsState(void);
u16 EReaderHandleTransfer(u8, size_t, const void *, void *); u16 EReaderHandleTransfer(u8 mode, size_t size, const void * src, void * dest);
#endif //GUARD_EREADER_HELPERS_H #endif //GUARD_EREADER_HELPERS_H
+83 -74
View File
@@ -2,24 +2,17 @@
#include "link.h" #include "link.h"
#include "ereader_helpers.h" #include "ereader_helpers.h"
enum {
EREADER_XFR_STATE_INIT,
EREADER_XFR_STATE_HANDSHAKE,
EREADER_XFR_STATE_START,
EREADER_XFR_STATE_TRANSFER,
};
struct SendRecvMgr struct SendRecvMgr
{ {
u8 sendOrRecv; u8 master_slave; // 0: clock slave; 1: clock master
u8 state; u8 state; // EREADER_XFR_STATE_*
u8 field_02; u8 xferState; // EREADER_XFER_*
u8 field_03; u8 checksumResult; // EREADER_CHECKSUM_*
u8 field_04; u8 cancellationReason; // EREADER_CANCEL_*
u32 * dataptr; u32 * dataptr; // Payload source or destination
int cursor; int cursor; // Index of the next word
int size; int size; // Last word index
u32 checksum; u32 checksum; // Validation checksum
}; };
static bool16 DetermineSendRecvState(u8); static bool16 DetermineSendRecvState(u8);
@@ -39,10 +32,9 @@ static u16 sSavedIme;
static u16 sSavedIe; static u16 sSavedIe;
static u16 sSavedTm3Cnt; static u16 sSavedTm3Cnt;
static u16 sSavedSioCnt; static u16 sSavedSioCnt;
static u16 sSavedSioCnt;
static u16 sSavedRCnt; static u16 sSavedRCnt;
int EReader_Send(size_t r6, const void * r5) int EReader_Send(size_t size, const void * src)
{ {
int result; int result;
EReaderHelper_SaveRegsState(); EReaderHelper_SaveRegsState();
@@ -53,18 +45,18 @@ int EReader_Send(size_t r6, const void * r5)
if (TEST_BUTTON(sJoyNew, B_BUTTON)) if (TEST_BUTTON(sJoyNew, B_BUTTON))
gShouldAdvanceLinkState = 2; gShouldAdvanceLinkState = 2;
sSendRecvStatus = EReaderHandleTransfer(1, r6, r5, NULL); sSendRecvStatus = EReaderHandleTransfer(1, size, src, NULL);
if ((sSendRecvStatus & 0x13) == 0x10) if ((sSendRecvStatus & 0x13) == 0x10) // checksum OK and xfer off
{ {
result = 0; result = 0;
break; break;
} }
else if (sSendRecvStatus & 8) else if (sSendRecvStatus & 8) // cancelled by player
{ {
result = 1; result = 1;
break; break;
} }
else if (sSendRecvStatus & 4) else if (sSendRecvStatus & 4) // timed out
{ {
result = 2; result = 2;
break; break;
@@ -81,7 +73,7 @@ int EReader_Send(size_t r6, const void * r5)
return result; return result;
} }
int EReader_Recv(void * r5) int EReader_Recv(void * dest)
{ {
int result; int result;
EReaderHelper_SaveRegsState(); EReaderHelper_SaveRegsState();
@@ -92,18 +84,18 @@ int EReader_Recv(void * r5)
if (TEST_BUTTON(sJoyNew, B_BUTTON)) if (TEST_BUTTON(sJoyNew, B_BUTTON))
gShouldAdvanceLinkState = 2; gShouldAdvanceLinkState = 2;
sSendRecvStatus = EReaderHandleTransfer(0, 0, NULL, r5); sSendRecvStatus = EReaderHandleTransfer(0, 0, NULL, dest);
if ((sSendRecvStatus & 0x13) == 0x10) if ((sSendRecvStatus & 0x13) == 0x10) // checksum OK and xfer off
{ {
result = 0; result = 0;
break; break;
} }
else if (sSendRecvStatus & 8) else if (sSendRecvStatus & 8) // cancelled by player
{ {
result = 1; result = 1;
break; break;
} }
else if (sSendRecvStatus & 4) else if (sSendRecvStatus & 4) // timed out
{ {
result = 2; result = 2;
break; break;
@@ -159,92 +151,98 @@ u16 EReaderHandleTransfer(u8 mode, size_t size, const void * data, void * recvBu
{ {
switch (sSendRecvMgr.state) switch (sSendRecvMgr.state)
{ {
case 0: case EREADER_XFR_STATE_INIT:
OpenSerialMulti(); OpenSerialMulti();
sSendRecvMgr.field_02 = 1; sSendRecvMgr.xferState = EREADER_XFER_EXE;
sSendRecvMgr.state = 1; sSendRecvMgr.state = EREADER_XFR_STATE_HANDSHAKE;
break; break;
case 1: case EREADER_XFR_STATE_HANDSHAKE:
if (DetermineSendRecvState(mode)) if (DetermineSendRecvState(mode))
EnableSio(); EnableSio();
if (gShouldAdvanceLinkState == 2) if (gShouldAdvanceLinkState == 2)
{ {
sSendRecvMgr.field_04 = 2; sSendRecvMgr.cancellationReason = EREADER_CANCEL_KEY;
sSendRecvMgr.state = 6; sSendRecvMgr.state = EREADER_XFR_STATE_DONE;
} }
// Progression is handled by the serial callback
break; break;
case 2: case EREADER_XFR_STATE_START:
OpenSerial32(); OpenSerial32();
SetUpTransferManager(size, data, recvBuffer); SetUpTransferManager(size, data, recvBuffer);
sSendRecvMgr.state = 3; sSendRecvMgr.state = EREADER_XFR_STATE_TRANSFER;
// fallthrough // fallthrough
case 3: case EREADER_XFR_STATE_TRANSFER:
if (gShouldAdvanceLinkState == 2) if (gShouldAdvanceLinkState == 2)
{ {
sSendRecvMgr.field_04 = 2; sSendRecvMgr.cancellationReason = EREADER_CANCEL_KEY;
sSendRecvMgr.state = 6; sSendRecvMgr.state = EREADER_XFR_STATE_DONE;
} }
else else
{ {
sCounter1++; sCounter1++;
sCounter2++; sCounter2++;
if (sSendRecvMgr.sendOrRecv == 0 && sCounter2 > 60) if (sSendRecvMgr.master_slave == 0 && sCounter2 > 60)
{ {
sSendRecvMgr.field_04 = 1; sSendRecvMgr.cancellationReason = EREADER_CANCEL_TIMEOUT;
sSendRecvMgr.state = 6; sSendRecvMgr.state = EREADER_XFR_STATE_DONE;
} }
if (sSendRecvMgr.field_02 != 2) if (sSendRecvMgr.xferState != EREADER_XFER_CHK)
{ {
if (sSendRecvMgr.sendOrRecv != 0 && sCounter1 > 2) if (sSendRecvMgr.master_slave != 0 && sCounter1 > 2)
{ {
EnableSio(); EnableSio();
sSendRecvMgr.field_02 = 2; sSendRecvMgr.xferState = EREADER_XFER_CHK;
} }
else else
{ {
EnableSio(); EnableSio();
sSendRecvMgr.field_02 = 2; sSendRecvMgr.xferState = EREADER_XFER_CHK;
} }
} }
} }
// Progression is handled by the serial callback
break; break;
case 4: case EREADER_XFR_STATE_TRANSFER_DONE:
OpenSerialMulti(); OpenSerialMulti();
sSendRecvMgr.state = 5; sSendRecvMgr.state = EREADER_XFR_STATE_CHECKSUM;
break; break;
case 5: case EREADER_XFR_STATE_CHECKSUM:
if (sSendRecvMgr.sendOrRecv == 1 && sCounter1 > 2) if (sSendRecvMgr.master_slave == 1 && sCounter1 > 2)
EnableSio(); EnableSio();
if (++sCounter1 > 60) if (++sCounter1 > 60)
{ {
sSendRecvMgr.field_04 = 1; sSendRecvMgr.cancellationReason = EREADER_CANCEL_TIMEOUT;
sSendRecvMgr.state = 6; sSendRecvMgr.state = EREADER_XFR_STATE_DONE;
} }
break; break;
case 6: // Progression is handled by the serial callback
if (sSendRecvMgr.field_02 != 0) case EREADER_XFR_STATE_DONE:
if (sSendRecvMgr.xferState != 0)
{ {
CloseSerial(); CloseSerial();
sSendRecvMgr.field_02 = 0; sSendRecvMgr.xferState = 0;
} }
break; break;
} }
return sSendRecvMgr.field_02 | (sSendRecvMgr.field_04 << 2) | (sSendRecvMgr.field_03 << 4); return
(sSendRecvMgr.xferState << EREADER_XFER_SHIFT)
| (sSendRecvMgr.cancellationReason << EREADER_CANCEL_SHIFT)
| (sSendRecvMgr.checksumResult << EREADER_CHECKSUM_SHIFT);
} }
static bool16 DetermineSendRecvState(u8 mode) static bool16 DetermineSendRecvState(u8 mode)
{ {
bool16 resp; bool16 resp;
if ((*(vu32 *)REG_ADDR_SIOCNT & (SIO_MULTI_SI | SIO_MULTI_SD)) == SIO_MULTI_SD && mode) if ((*(vu32 *)REG_ADDR_SIOCNT & (SIO_MULTI_SI | SIO_MULTI_SD)) == SIO_MULTI_SD && mode)
resp = sSendRecvMgr.sendOrRecv = TRUE; resp = sSendRecvMgr.master_slave = TRUE;
else else
resp = sSendRecvMgr.sendOrRecv = FALSE; resp = sSendRecvMgr.master_slave = FALSE;
return resp; return resp;
} }
static void SetUpTransferManager(size_t size, const void * data, void * recvBuffer) static void SetUpTransferManager(size_t size, const void * data, void * recvBuffer)
{ {
if (sSendRecvMgr.sendOrRecv) if (sSendRecvMgr.master_slave)
{ {
REG_SIOCNT |= SIO_38400_BPS; REG_SIOCNT |= SIO_38400_BPS;
sSendRecvMgr.dataptr = (void *)data; sSendRecvMgr.dataptr = (void *)data;
@@ -284,7 +282,7 @@ void EReaderHelper_SerialCallback(void)
switch (sSendRecvMgr.state) switch (sSendRecvMgr.state)
{ {
case 1: case EREADER_XFR_STATE_HANDSHAKE:
REG_SIOMLT_SEND = 0xCCD0; REG_SIOMLT_SEND = 0xCCD0;
*(u64 *)recv = REG_SIOMLT_RECV; *(u64 *)recv = REG_SIOMLT_RECV;
for (i = 0, cnt1 = 0, cnt2 = 0; i < 4; i++) for (i = 0, cnt1 = 0, cnt2 = 0; i < 4; i++)
@@ -295,14 +293,17 @@ void EReaderHelper_SerialCallback(void)
cnt2++; cnt2++;
} }
if (cnt1 == 2 && cnt2 == 0) if (cnt1 == 2 && cnt2 == 0)
sSendRecvMgr.state = 2; sSendRecvMgr.state = EREADER_XFR_STATE_START;
break; break;
case 3: // Progression is handled by software
case EREADER_XFR_STATE_TRANSFER:
recv32 = REG_SIODATA32; recv32 = REG_SIODATA32;
if (sSendRecvMgr.cursor == 0 && sSendRecvMgr.sendOrRecv == 0) // The first value sent by the EReader is the payload size
if (sSendRecvMgr.cursor == 0 && sSendRecvMgr.master_slave == 0)
sSendRecvMgr.size = recv32 / 4 + 1; sSendRecvMgr.size = recv32 / 4 + 1;
if (sSendRecvMgr.sendOrRecv == 1) if (sSendRecvMgr.master_slave == 1)
{ {
// Send mode
if (sSendRecvMgr.cursor < sSendRecvMgr.size) if (sSendRecvMgr.cursor < sSendRecvMgr.size)
{ {
REG_SIODATA32 = sSendRecvMgr.dataptr[sSendRecvMgr.cursor]; REG_SIODATA32 = sSendRecvMgr.dataptr[sSendRecvMgr.cursor];
@@ -313,43 +314,51 @@ void EReaderHelper_SerialCallback(void)
} }
else else
{ {
// Receive mode
if (sSendRecvMgr.cursor > 0 && sSendRecvMgr.cursor < sSendRecvMgr.size + 1) if (sSendRecvMgr.cursor > 0 && sSendRecvMgr.cursor < sSendRecvMgr.size + 1)
{ {
// Receive next word
sSendRecvMgr.dataptr[sSendRecvMgr.cursor - 1] = recv32; sSendRecvMgr.dataptr[sSendRecvMgr.cursor - 1] = recv32;
sSendRecvMgr.checksum += recv32; sSendRecvMgr.checksum += recv32;
} }
else if (sSendRecvMgr.cursor != 0) else if (sSendRecvMgr.cursor != 0)
{ {
// Reached the end, test the received checksum
if (sSendRecvMgr.checksum == recv32) if (sSendRecvMgr.checksum == recv32)
sSendRecvMgr.field_03 = 1; sSendRecvMgr.checksumResult = EREADER_CHECKSUM_OK;
else else
sSendRecvMgr.field_03 = 2; sSendRecvMgr.checksumResult = EREADER_CHECKSUM_ERR;
} }
sCounter2 = 0; sCounter2 = 0;
} }
sSendRecvMgr.cursor++; sSendRecvMgr.cursor++;
if (sSendRecvMgr.cursor < sSendRecvMgr.size + 2) if (sSendRecvMgr.cursor < sSendRecvMgr.size + 2)
{ {
if (sSendRecvMgr.sendOrRecv != 0) if (sSendRecvMgr.master_slave != 0)
// Clock master; start timer
REG_TM3CNT_H |= TIMER_ENABLE; REG_TM3CNT_H |= TIMER_ENABLE;
else else
// Clock slave; reset
EnableSio(); EnableSio();
} }
else else
{ {
sSendRecvMgr.state = 4; sSendRecvMgr.state = EREADER_XFR_STATE_TRANSFER_DONE;
sCounter1 = 0; sCounter1 = 0;
} }
break; break;
case 5: // Progression is handled by the software
if (sSendRecvMgr.sendOrRecv == 0) case EREADER_XFR_STATE_CHECKSUM:
REG_SIODATA8 = sSendRecvMgr.field_03; if (sSendRecvMgr.master_slave == 0)
// Clock slave
REG_SIODATA8 = sSendRecvMgr.checksumResult;
*(vu64 *)recv = REG_SIOMLT_RECV; *(vu64 *)recv = REG_SIOMLT_RECV;
if (recv[1] == 1 || recv[1] == 2) if (recv[1] == EREADER_CHECKSUM_OK || recv[1] == EREADER_CHECKSUM_ERR)
{ {
if (sSendRecvMgr.sendOrRecv == 1) if (sSendRecvMgr.master_slave == 1)
sSendRecvMgr.field_03 = recv[1]; // EReader has (in)validated the payload
sSendRecvMgr.state = 6; sSendRecvMgr.checksumResult = recv[1];
sSendRecvMgr.state = EREADER_XFR_STATE_DONE;
} }
break; break;
} }
+4 -4
View File
@@ -9,7 +9,7 @@
#include "decompress.h" #include "decompress.h"
#include "link.h" #include "link.h"
#include "link_rfu.h" #include "link_rfu.h"
#include "unk_815c27c.h" #include "ereader_helpers.h"
#include "util.h" #include "util.h"
#include "script.h" #include "script.h"
#include "event_data.h" #include "event_data.h"
@@ -108,11 +108,11 @@ u8 SendUnknownSerialData_Run(struct MEvent_Str_1 *mgr)
{ {
u8 resp = 0; u8 resp = 0;
mgr->status = EReaderHandleTransfer(1, mgr->size, mgr->data, 0); mgr->status = EReaderHandleTransfer(1, mgr->size, mgr->data, 0);
if ((mgr->status & 0x13) == 0x10) if ((mgr->status & 0x13) == 0x10) // checksum OK and xfer off
resp = 1; resp = 1;
if (mgr->status & 8) if (mgr->status & 8) // cancelled by player
resp = 2; resp = 2;
if (mgr->status & 4) if (mgr->status & 4) // timed out
resp = 3; resp = 3;
gShouldAdvanceLinkState = 0; gShouldAdvanceLinkState = 0;
return resp; return resp;