summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjiangzhengwenjz <jiangzhengwenjzw@qq.com>2019-12-31 06:42:18 +0800
committerjiangzhengwenjz <jiangzhengwenjzw@qq.com>2020-01-09 12:38:57 +0800
commit6cbce0b9668c0fd7e902397e96f9a488b1d6f5a8 (patch)
tree0cd5ff732dc7fee2e7aa7ec8c421afec2ff44043 /src
parent973cb394b23002acde7d7ea19abc754019dd106c (diff)
librfu through 0x81E2C40
Diffstat (limited to 'src')
-rw-r--r--src/librfu_rfu.c1095
1 files changed, 1093 insertions, 2 deletions
diff --git a/src/librfu_rfu.c b/src/librfu_rfu.c
index 96f4e9519..3bfa3b601 100644
--- a/src/librfu_rfu.c
+++ b/src/librfu_rfu.c
@@ -11,17 +11,31 @@ void rfu_CB_startSearchParent(u8, u16);
void rfu_CB_pollSearchParent(u8, u16);
void rfu_CB_pollConnectParent(u8, u16);
void rfu_CB_pollConnectParent(u8, u16);
+void rfu_CB_disconnect(u8, u16);
+void rfu_CB_CHILD_pollConnectRecovery(u8, u16);
+void rfu_CB_sendData(UNUSED u8, u16);
+void rfu_CB_sendData2(UNUSED u8, u16);
+void rfu_CB_sendData3(u8, u16);
+void rfu_CB_recvData(u8, u16);
s32 sub_81E349C(u8);
void rfu_enableREQCallback(bool8);
void rfu_STC_readChildList(void);
void rfu_STC_readParentCandidateList(void);
void rfu_STC_REQ_callback(u8, u16);
void rfu_STC_removeLinkData(u8, u8);
-void rfu_STC_fastCopy(u8 **a1, u8 **a2, s32 a3);
+void rfu_STC_fastCopy(const u8 **, u8 **, s32);
void rfu_STC_clearLinkStatus(u8);
void rfu_NI_checkCommFailCounter(void);
+u16 rfu_STC_setSendData_org(u8, u8, u8, const void *, u32);
+void rfu_constructSendLLFrame(void);
+u16 rfu_STC_NI_constructLLSF(u8, u8 **, struct NIComm *);
+u16 rfu_STC_UNI_constructLLSF(u8, u8 **);
+void rfu_STC_PARENT_analyzeRecvPacket(void);
+void rfu_STC_CHILD_analyzeRecvPacket(void);
+u16 rfu_STC_analyzeLLSF(u8, u8 *, u16);
extern const char _Str_RFU_MBOOT[];
+extern const u8 _Str_RfuHeader[];
struct RfuStruct *gRfuState;
ALIGNED(8) struct RfuSlotStatusUNI *gRfuSlotStatusUNI[4];
@@ -89,7 +103,7 @@ u16 rfu_initializeAPI(struct Unk_3001190 *unk0, u16 unk1, IntrFunc *interrupt, b
// rfu_REQ_changeMasterSlave is the function next to rfu_STC_fastCopy
for (r3 = ((void *)rfu_REQ_changeMasterSlave - (void *)rfu_STC_fastCopy) / sizeof(u16), --r3; r3 != 0xFFFF; --r3)
*dst++ = *src++;
- gRfuFixed->fastCopyPtr = (u8 *)gRfuFixed->fastCopyBuffer + 1;
+ gRfuFixed->fastCopyPtr = (void *)gRfuFixed->fastCopyBuffer + 1;
return 0;
}
@@ -734,3 +748,1080 @@ u16 rfu_syncVBlank(void)
--gRfuStatic->watchdogTimer;
return 0;
}
+
+s32 rfu_REQBN_watchLink(u16 r5, u8 *r8, u8 *sp00, u8 *sp04)
+{
+ u8 sp08 = 0;
+ u8 sp0C = 0;
+ u8 i;
+ s32 sp10, sp14;
+ u8 *r2;
+ u8 r9, r6, r3, r1, r0;
+
+ *r8 = 0;
+ *sp00 = 0;
+ *sp04 = 0;
+ if (gRfuLinkStatus->connMode == 0xFF || gRfuState->msMode == 0)
+ return 0;
+ if (gRfuStatic->flags & 4)
+ gRfuStatic->watchdogTimer = 360;
+ if (gRfuStatic->nowWatchInterval == 0)
+ {
+ gRfuStatic->nowWatchInterval = gRfuLinkStatus->watchInterval;
+ sp08 = 1;
+ }
+ if ((u8)r5 == 41)
+ {
+ u8 *r1 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data;
+
+ *r8 = r1[4];
+ *sp00 = r1[5];
+ if (*sp00 == 1)
+ *r8 = gRfuLinkStatus->connSlotFlag;
+ sp08 = 2;
+ }
+ else
+ {
+ if (r5 == 310)
+ {
+ r6 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[5];
+ r6 ^= gRfuLinkStatus->connSlotFlag;
+ *r8 = r6 & gRfuLinkStatus->connSlotFlag;
+ *sp00 = 1;
+ for (i = 0; i < NELEMS(gRfuLinkStatus->strength); ++i)
+ {
+ if ((*r8 >> i) & 1)
+ {
+ gRfuLinkStatus->strength[i] = 0;
+ rfu_STC_removeLinkData(i, 0);
+ }
+ }
+ }
+ if (sp08 == 0)
+ return 0;
+ }
+ sp10 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket32.command;
+ sp14 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket32.data[0];
+ STWI_set_Callback_M(rfu_CB_defaultCallback);
+ STWI_send_LinkStatusREQ();
+ sp0C = STWI_poll_CommandEnd();
+ if (sp0C == 0)
+ {
+ r2 = &gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[4];
+ for (i = 0; i < NELEMS(gRfuLinkStatus->strength); ++i)
+ gRfuLinkStatus->strength[i] = *r2++;
+ r9 = 0;
+ i = 0;
+ }
+ else
+ {
+ rfu_STC_REQ_callback(17, sp0C);
+ return sp0C;
+ }
+ for (; i < 4; ++i)
+ {
+ r6 = 1 << i;
+ if (sp0C == 0)
+ {
+ if (sp08 == 1 && (gRfuLinkStatus->connSlotFlag & r6))
+ {
+ if (gRfuLinkStatus->strength[i] == 0)
+ {
+ if (gRfuLinkStatus->connMode == 1)
+ {
+ ++gRfuStatic->linkEmergencyFlag[i];
+ if (gRfuStatic->linkEmergencyFlag[i] > 3)
+ {
+ *r8 |= r6;
+ *sp00 = sp08; // why not directly use 1?
+ }
+ }
+ else
+ {
+ STWI_send_SystemStatusREQ();
+ if (STWI_poll_CommandEnd() == 0)
+ {
+ if (gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[7] == 0)
+ {
+ *r8 |= r6;
+ *sp00 = sp08;
+ }
+ else
+ {
+ if (++gRfuStatic->linkEmergencyFlag[i] > gRfuStatic->unk_1a)
+ {
+ gRfuStatic->linkEmergencyFlag[i] = 0;
+ STWI_send_DisconnectREQ(gRfuLinkStatus->connSlotFlag);
+ STWI_poll_CommandEnd();
+ *r8 |= r6;
+ *sp00 = sp08; // why not directly use 1?
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ gRfuStatic->linkEmergencyFlag[i] = sp0C; // why not directly use 0?
+ }
+ }
+ if (gRfuLinkStatus->connMode == 1 && gRfuLinkStatus->strength[i] != 0)
+ {
+ if (r6 & gRfuLinkStatus->linkLossSlotFlag)
+ {
+ if (gRfuLinkStatus->strength[i] > 10)
+ {
+ *sp04 |= r6;
+ gRfuLinkStatus->connSlotFlag |= r6;
+ gRfuLinkStatus->linkLossSlotFlag &= ~r6;
+ ++gRfuLinkStatus->connCount;
+ gRfuStatic->linkEmergencyFlag[i] = 0;
+ }
+ else
+ {
+ gRfuLinkStatus->strength[i] = 0;
+ }
+ }
+ else
+ {
+ if (!((gRfuLinkStatus->connSlotFlag | gRfuLinkStatus->linkLossSlotFlag) & r6))
+ {
+ STWI_send_SlotStatusREQ();
+ STWI_poll_CommandEnd();
+ r2 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data;
+ r3 = r2[1] - 1;
+ for (r2 += 8; r3 != 0; r2 += 4, --r3)
+ {
+ u16 r4 = *(u16 *)r2;
+
+ if (r2[2] == i && r4 == gRfuStatic->cidBak[i])
+ {
+ r9 |= 1 << i;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ r1 = gRfuLinkStatus->connSlotFlag;
+ r0 = *r8;
+ r0 &= r1;
+ if (r6 & r0)
+ rfu_STC_removeLinkData(i, 0);
+ }
+ if (r9 != 0)
+ {
+ STWI_send_DisconnectREQ(r9);
+ STWI_poll_CommandEnd();
+ }
+ // equivalent to:
+ // gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket32.command = sp10;
+ *(u32 *)gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data = sp10;
+ gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket32.data[0] = sp14;
+ return 0;
+}
+
+void rfu_STC_removeLinkData(u8 r7, u8 r12)
+{
+ u8 r5 = 1 << r7;
+ s32 r6;
+
+ if ((gRfuLinkStatus->connSlotFlag & r5) && gRfuLinkStatus->connCount != 0)
+ --gRfuLinkStatus->connCount;
+ gRfuLinkStatus->connSlotFlag &= r6 = ~r5;
+ gRfuLinkStatus->linkLossSlotFlag |= r5;
+ if ((*(u32 *)gRfuLinkStatus & 0xFF00FF) == 0)
+ gRfuLinkStatus->connMode = 0xFF;
+ if (r12 != 0)
+ {
+ CpuFill16(0, &gRfuLinkStatus->partner[r7], sizeof(struct RfuTgtData));
+ gRfuLinkStatus->linkLossSlotFlag &= r6;
+ gRfuLinkStatus->getNameFlag &= r6;
+ gRfuLinkStatus->strength[r7] = 0;
+ }
+}
+
+void rfu_REQ_disconnect(u8 who)
+{
+ u16 r1;
+
+ if ((gRfuLinkStatus->connSlotFlag | gRfuLinkStatus->linkLossSlotFlag) & who)
+ {
+ gRfuStatic->recoveryBmSlot = who;
+ if (gRfuLinkStatus->connMode == 0xFF && gRfuStatic->flags & 0x80)
+ {
+ if (gRfuLinkStatus->linkLossSlotFlag & who)
+ rfu_CB_disconnect(48, 0);
+ }
+ else if (gRfuStatic->SCStartFlag
+ && (STWI_set_Callback_M(rfu_CB_defaultCallback),
+ STWI_send_SC_EndREQ(),
+ (r1 = STWI_poll_CommandEnd()) != 0))
+ {
+ rfu_STC_REQ_callback(27, r1);
+ }
+ else
+ {
+ STWI_set_Callback_M(rfu_CB_disconnect);
+ STWI_send_DisconnectREQ(who);
+ }
+ }
+}
+
+void rfu_CB_disconnect(u8 r6, u16 r5)
+{
+ u8 r4, r0;
+
+ if (r5 == 3 && gRfuLinkStatus->connMode == 0)
+ {
+ STWI_set_Callback_M(rfu_CB_defaultCallback);
+ STWI_send_SystemStatusREQ();
+ if (STWI_poll_CommandEnd() == 0 && gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[7] == 0)
+ r5 = 0;
+ }
+ gRfuStatic->recoveryBmSlot &= gRfuLinkStatus->connSlotFlag | gRfuLinkStatus->linkLossSlotFlag;
+ gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[8] = gRfuStatic->recoveryBmSlot;
+ if (r5 == 0)
+ {
+ for (r4 = 0; r4 < 4; ++r4)
+ {
+ r0 = 1 << r4;
+ if (r0 & gRfuStatic->recoveryBmSlot)
+ rfu_STC_removeLinkData(r4, 1);
+ }
+ }
+ if ((gRfuLinkStatus->connSlotFlag | gRfuLinkStatus->linkLossSlotFlag) == 0)
+ gRfuLinkStatus->connMode = 0xFF;
+ rfu_STC_REQ_callback(r6, r5);
+ if (gRfuStatic->SCStartFlag)
+ {
+ STWI_set_Callback_M(rfu_CB_defaultCallback);
+ STWI_send_SC_StartREQ();
+ r5 = STWI_poll_CommandEnd();
+ if (r5 != 0)
+ rfu_STC_REQ_callback(25, r5);
+ }
+}
+
+void rfu_REQ_CHILD_startConnectRecovery(u8 r5)
+{
+ u8 i;
+
+ gRfuStatic->recoveryBmSlot = r5;
+ for (i = 0; i < 4 && !((r5 >> i) & 1); ++i)
+ ;
+ STWI_set_Callback_M(rfu_STC_REQ_callback);
+ // if i == 4, gRfuLinkStatus->partner[i].id becomes gRfuLinkStatus->my.id
+ STWI_send_CPR_StartREQ(gRfuLinkStatus->partner[i].id, gRfuLinkStatus->my.id, r5);
+}
+
+void rfu_REQ_CHILD_pollConnectRecovery(void)
+{
+ STWI_set_Callback_M(rfu_CB_CHILD_pollConnectRecovery);
+ STWI_send_CPR_PollingREQ();
+}
+
+void rfu_CB_CHILD_pollConnectRecovery(u8 r8, u16 r7)
+{
+ u8 r3, r4;
+ struct RfuLinkStatus *r2;
+
+ if (r7 == 0 && gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[4] == 0 && gRfuStatic->recoveryBmSlot)
+ {
+ gRfuLinkStatus->connMode = 0;
+ for (r4 = 0; r4 < NELEMS(gRfuStatic->linkEmergencyFlag); ++r4)
+ {
+ r3 = 1 << r4;
+ r2 = gRfuLinkStatus; // ???
+ if (gRfuStatic->recoveryBmSlot & r3 & r2->linkLossSlotFlag)
+ {
+ gRfuLinkStatus->connSlotFlag |= r3;
+ gRfuLinkStatus->linkLossSlotFlag &= ~r3;
+ ++gRfuLinkStatus->connCount;
+ gRfuStatic->linkEmergencyFlag[r4] = 0;
+ }
+ }
+ gRfuStatic->recoveryBmSlot = 0;
+ }
+ rfu_STC_REQ_callback(r8, r7);
+}
+
+u16 rfu_CHILD_getConnectRecoveryStatus(u8 *status)
+{
+ u8 r0;
+
+ *status = 0xFF;
+ r0 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[0] + 77;
+ if (r0 <= 1)
+ {
+ *status = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[4];
+ return 0;
+ }
+ return 0x10;
+}
+
+void rfu_REQ_CHILD_endConnectRecovery(void)
+{
+ STWI_set_Callback_M(rfu_CB_CHILD_pollConnectRecovery);
+ STWI_send_CPR_EndREQ();
+}
+
+void rfu_STC_fastCopy(const u8 **src_p, u8 **dst_p, s32 size)
+{
+ const u8 *src = *src_p;
+ u8 *dst = *dst_p;
+ s32 i;
+
+ for (i = size - 1; i != -1; --i)
+ *dst++ = *src++;
+ *src_p = src;
+ *dst_p = dst;
+}
+
+void rfu_REQ_changeMasterSlave(void)
+{
+ if (STWI_read_status(1) == 1)
+ {
+ STWI_set_Callback_M(rfu_STC_REQ_callback);
+ STWI_send_MS_ChangeREQ();
+ }
+ else
+ {
+ rfu_STC_REQ_callback(39, 0);
+ }
+}
+
+bool8 rfu_getMasterSlave(void)
+{
+ bool8 r2 = STWI_read_status(1);
+
+ if (r2 == 1)
+ {
+ if (gRfuState->unk_2c)
+ {
+ if (gRfuState->reqActiveCommand == 39
+ || gRfuState->reqActiveCommand == 37
+ || gRfuState->reqActiveCommand == 55)
+ r2 = 0;
+ }
+ }
+ return r2;
+}
+
+void rfu_clearAllSlot(void)
+{
+ u16 i;
+ u16 IMEBackup = REG_IME;
+
+ REG_IME = 0;
+ for (i = 0; i < NELEMS(gRfuSlotStatusNI); ++i)
+ {
+ CpuFill16(0, gRfuSlotStatusNI[i], sizeof(gRfuSlotStatusNI[i]->sub));
+ CpuFill16(0, gRfuSlotStatusUNI[i], sizeof(gRfuSlotStatusUNI[i]->sub));
+ gRfuLinkStatus->remainLLFrameSizeChild[i] = 16;
+ }
+ gRfuLinkStatus->remainLLFrameSizeParent = 87;
+ gRfuLinkStatus->sendSlotNIFlag = 0;
+ gRfuLinkStatus->recvSlotNIFlag = 0;
+ gRfuLinkStatus->sendSlotUNIFlag = 0;
+ gRfuStatic->recvRenewalFlag = 0;
+ REG_IME = IMEBackup;
+}
+
+void rfu_STC_releaseFrame(u8 r5, u8 r3, struct NIComm *r4)
+{
+
+ if (!(gRfuStatic->flags & 0x80))
+ {
+ if (r3 == 0)
+ gRfuLinkStatus->remainLLFrameSizeParent += r4->payloadSize;
+ gRfuLinkStatus->remainLLFrameSizeParent += 3;
+ }
+ else
+ {
+ if (r3 == 0)
+ gRfuLinkStatus->remainLLFrameSizeChild[r5] += r4->payloadSize;
+ gRfuLinkStatus->remainLLFrameSizeChild[r5] += 2;
+ }
+}
+
+s32 rfu_clearSlot(u8 r8, u8 r7)
+{
+ u16 r10, r3, r1;
+ struct NIComm *r4;
+
+ if (r7 > 3)
+ return 0x400;
+ if ((r8 & 0xF) == 0)
+ return 0x600;
+ r10 = REG_IME;
+ REG_IME = 0;
+ if (r8 & 0xC)
+ {
+ for (r3 = 0; r3 < 2; ++r3)
+ {
+ r4 = NULL;
+ if (r3 == 0)
+ {
+ if (r8 & 4)
+ {
+ r4 = &gRfuSlotStatusNI[r7]->sub.send;
+ gRfuLinkStatus->sendSlotNIFlag &= ~r4->bmSlotOrg;
+ }
+ }
+ else
+ {
+ if (r8 & 8)
+ {
+ r4 = &gRfuSlotStatusNI[r7]->sub.recv;
+ gRfuLinkStatus->recvSlotNIFlag &= ~(1 << r7);
+ }
+ }
+ if (r4 != NULL)
+ {
+ if (r4->state & 0x8000)
+ {
+ rfu_STC_releaseFrame(r7, r3, r4);
+ for (r1 = 0; r1 < 4; ++r1)
+ if ((r4->bmSlotOrg >> r1) & 1)
+ r4->failCounter = 0;
+ }
+ CpuFill16(0, r4, sizeof(struct NIComm));
+ }
+ }
+ }
+ if (r8 & 1)
+ {
+ struct RfuSlotStatusUNI *r3 = gRfuSlotStatusUNI[r7];
+
+ if (r3->sub.send.state & 0x8000)
+ {
+ if (!(gRfuStatic->flags & 0x80))
+ gRfuLinkStatus->remainLLFrameSizeParent += 3 + (u8)r3->sub.send.payloadSize;
+ else
+ gRfuLinkStatus->remainLLFrameSizeChild[r7] += 2 + (u8)r3->sub.send.payloadSize;
+ gRfuLinkStatus->sendSlotUNIFlag &= ~r3->sub.send.bmSlot;
+ }
+ CpuFill16(0, &r3->sub.send, sizeof(struct UNISend));
+ }
+ if (r8 & 2)
+ {
+ CpuFill16(0, &gRfuSlotStatusUNI[r7]->sub.recv, sizeof(struct UNIRecv));
+ }
+ REG_IME = r10;
+ return 0;
+}
+
+s32 rfu_setRecvBuffer(u8 r3, u8 r4, void *r5, size_t r6)
+{
+ if (r4 > 3)
+ return 0x400;
+ if (r3 & 0x20)
+ {
+ gRfuSlotStatusNI[r4]->recvBuffer = r5;
+ gRfuSlotStatusNI[r4]->recvBufferSize = r6;
+ }
+ else if (!(r3 & 0x10))
+ {
+ return 0x600;
+ }
+ else
+ {
+ gRfuSlotStatusUNI[r4]->recvBuffer = r5;
+ gRfuSlotStatusUNI[r4]->recvBufferSize = r6;
+ }
+ return 0;
+}
+
+s32 rfu_NI_setSendData(u8 a1, u8 a2, const void *a3, u32 a4)
+{
+ return rfu_STC_setSendData_org(32, a1, a2, a3, a4);
+}
+
+s32 rfu_UNI_setSendData(u8 flag, const void *ptr, u8 size)
+{
+ u8 r0;
+
+ if (gRfuLinkStatus->connMode == 1)
+ r0 = size + 3;
+ else
+ r0 = size + 2;
+ return rfu_STC_setSendData_org(16, flag, r0, ptr, 0);
+}
+
+s32 rfu_NI_CHILD_setSendGameName(u8 a1, u8 a2)
+{
+ return rfu_STC_setSendData_org(64, 1 << a1, a2, &gRfuLinkStatus->my.serialNum, 26);
+}
+
+u16 rfu_STC_setSendData_org(u8 r6, u8 r3, u8 r8, const void *sp00, u32 sp28)
+{
+ u8 r2, r0;
+ u8 r4;
+ u8 *r9;
+ u8 r5;
+ u8 i;
+ u16 sp04;
+ struct RfuSlotStatusUNI *r1;
+ struct RfuSlotStatusNI *r12;
+
+ if (gRfuLinkStatus->connMode == 0xFF)
+ return 0x301;
+ if (!(r3 & 0xF))
+ return 0x400;
+ if (((gRfuLinkStatus->connSlotFlag | gRfuLinkStatus->linkLossSlotFlag) & r3) != r3)
+ return 0x401;
+ if (r6 & 0x10)
+ r0 = gRfuLinkStatus->sendSlotUNIFlag;
+ else
+ r0 = gRfuLinkStatus->sendSlotNIFlag;
+ if (r0 & r3)
+ return 0x402;
+ for (r2 = 0; r2 < 4 && !((r3 >> r2) & 1); ++r2)
+ ;
+ if (gRfuLinkStatus->connMode == 1)
+ r9 = &gRfuLinkStatus->remainLLFrameSizeParent;
+ else if (gRfuLinkStatus->connMode == 0)
+ r9 = &gRfuLinkStatus->remainLLFrameSizeChild[r2];
+ r4 = _Str_RfuHeader[16 * gRfuLinkStatus->connMode];
+ if (r8 > *r9 || r8 <= r4)
+ return 0x500;
+ sp04 = REG_IME;
+ REG_IME = 0;
+ r5 = r6 & 0x20;
+ if (r5 || r6 == 0x40)
+ {
+ u8 *r1; // a hack to swap instructions
+
+ r12 = gRfuSlotStatusNI[r2];
+ r1 = NULL;
+ r12->sub.send.errorCode = 0;
+ *r12->sub.send.nowP = r1 = &r12->sub.send.dataType;
+ r12->sub.send.remainSize = 7;
+ r12->sub.send.bmSlotOrg = r3;
+ r12->sub.send.bmSlot = r3;
+ r12->sub.send.payloadSize = r8 - r4;
+ if (r5 != 0)
+ *r1 = 0;
+ else
+ *r1 = 1;
+ r12->sub.send.dataSize = sp28;
+ r12->sub.send.src = sp00;
+ r12->sub.send.ack = 0;
+ r12->sub.send.phase = 0;
+ #ifndef NONMATCHING // to fix r2, r3, r4, r5 register roulette
+ asm("":::"r2");
+ #endif
+ for (i = 0; i < NELEMS(r12->sub.send.recvAckFlag); ++i)
+ {
+ r12->sub.send.recvAckFlag[i] = 0;
+ r12->sub.send.n[i] = 1;
+ }
+ for (r2 = 0; r2 < NELEMS(gRfuSlotStatusNI); ++r2)
+ if ((r3 >> r2) & 1)
+ gRfuSlotStatusNI[r2]->sub.send.failCounter = 0;
+ gRfuLinkStatus->sendSlotNIFlag |= r3;
+ *r9 -= r8;
+ r12->sub.send.state = 0x8021;
+ }
+ else if (r6 & 0x10)
+ {
+ r1 = gRfuSlotStatusUNI[r2];
+ r1->sub.send.bmSlot = r3;
+ r1->sub.send.src = sp00;
+ r1->sub.send.payloadSize = r8 - r4;
+ *r9 -= r8;
+ r1->sub.send.state = 0x8024;
+ gRfuLinkStatus->sendSlotUNIFlag |= r3;
+ }
+ REG_IME = sp04;
+ return 0;
+}
+
+s32 rfu_changeSendTarget(u8 r3, u8 r7, u8 r6)
+{
+ struct RfuSlotStatusNI *r5;
+ u16 r8;
+ u8 r2;
+
+ if (r7 >= NELEMS(gRfuSlotStatusNI))
+ return 0x400;
+ if (r3 == 0x20)
+ {
+ r5 = gRfuSlotStatusNI[r7];
+ if ((r5->sub.send.state & 0x8000)
+ && (r5->sub.send.state & 0x20))
+ {
+ r3 = r6 ^ r5->sub.send.bmSlot;
+
+ if (!(r3 & r6))
+ {
+ if (r3)
+ {
+ r8 = REG_IME;
+ REG_IME = 0;
+ for (r2 = 0; r2 < NELEMS(gRfuSlotStatusNI); ++r2)
+ {
+ if ((r3 >> r2) & 1)
+ gRfuSlotStatusNI[r2]->sub.send.failCounter = 0;
+ }
+ gRfuLinkStatus->sendSlotNIFlag &= ~r3;
+ r5->sub.send.bmSlot = r6;
+ if ((r6 << 24) == 0) // The shift doesn't make any sense.
+ {
+ rfu_STC_releaseFrame(r7, 0, &r5->sub.send);
+ r5->sub.send.state = 39;
+ }
+ REG_IME = r8;
+ }
+ }
+ else
+ {
+ return 0x404;
+ }
+ }
+ else
+ {
+ return 0x403;
+ }
+ }
+ else
+ {
+ if (r3 == 16)
+ {
+ s32 r3;
+
+ if (gRfuSlotStatusUNI[r7]->sub.send.state != 0x8024)
+ return 0x403;
+ for (r3 = 0, r2 = 0; r2 < NELEMS(gRfuSlotStatusUNI); ++r2)
+ if (r2 != r7)
+ r3 |= gRfuSlotStatusUNI[r2]->sub.send.bmSlot;
+ if (r6 & r3)
+ return 0x404;
+ r8 = REG_IME;
+ REG_IME = 0;
+ gRfuLinkStatus->sendSlotUNIFlag &= ~gRfuSlotStatusUNI[r7]->sub.send.bmSlot;
+ gRfuLinkStatus->sendSlotUNIFlag |= r6;
+ gRfuSlotStatusUNI[r7]->sub.send.bmSlot = r6;
+ REG_IME = r8;
+ }
+ else
+ {
+ return 0x600;
+ }
+ }
+ return 0;
+}
+
+s32 rfu_NI_stopReceivingData(u8 who)
+{
+#ifndef NONMATCHING // r4, r5 register swap
+ register struct NIComm *r5 asm("r5");
+#else
+ struct NIComm *r5;
+#endif
+ u16 r4, r1;
+
+ if (who > 3)
+ return 0x400;
+ r5 = &gRfuSlotStatusNI[who]->sub.recv;
+ r4 = REG_IME;
+ REG_IME = 0;
+ if (gRfuSlotStatusNI[who]->sub.recv.state & 0x8000)
+ {
+ if (gRfuSlotStatusNI[who]->sub.recv.state == 0x8043)
+ gRfuSlotStatusNI[who]->sub.recv.state = 72;
+ else
+ gRfuSlotStatusNI[who]->sub.recv.state = 71;
+ gRfuLinkStatus->recvSlotNIFlag &= ~(1 << who);
+ rfu_STC_releaseFrame(who, 1, r5);
+ }
+ REG_IME = r4;
+ return 0;
+}
+
+s32 rfu_UNI_changeAndReadySendData(u8 r3, const void *r7, u8 r5)
+{
+ struct UNISend *r4;
+ u8 *r6;
+ u16 r1;
+ u8 r3_;
+
+ if (r3 >= 4)
+ return 0x400;
+ r4 = &gRfuSlotStatusUNI[r3]->sub.send;
+ if (r4->state != 0x8024)
+ return 0x403;
+ if (gRfuLinkStatus->connMode == 1)
+ {
+ r6 = &gRfuLinkStatus->remainLLFrameSizeParent;
+ r3_ = gRfuLinkStatus->remainLLFrameSizeParent + (u8)r4->payloadSize;
+ }
+ else
+ {
+ r6 = &gRfuLinkStatus->remainLLFrameSizeChild[r3];
+ r3_ = gRfuLinkStatus->remainLLFrameSizeChild[r3] + (u8)r4->payloadSize;
+ }
+ if (r3_ < r5)
+ return 0x500;
+ r1 = REG_IME;
+ REG_IME = 0;
+ r4->src = r7;
+ *r6 = r3_ - r5;
+ r4->payloadSize = r5;
+ r4->dataReadyFlag = 1;
+ REG_IME = r1;
+ return 0;
+}
+
+void rfu_UNI_readySendData(u8 a1)
+{
+ if (a1 < NELEMS(gRfuSlotStatusUNI))
+ {
+ if (gRfuSlotStatusUNI[a1]->sub.send.state == 0x8024)
+ gRfuSlotStatusUNI[a1]->sub.send.dataReadyFlag = 1;
+ }
+}
+
+void rfu_UNI_clearRecvNewDataFlag(u8 a1)
+{
+ if (a1 < NELEMS(gRfuSlotStatusUNI))
+ gRfuSlotStatusUNI[a1]->sub.recv.newDataFlag = 0;
+}
+
+void rfu_REQ_sendData(u8 r5)
+{
+ if (gRfuLinkStatus->connMode != 0xFF)
+ {
+ if (gRfuLinkStatus->connMode == 1
+ && !(gRfuLinkStatus->sendSlotNIFlag | gRfuLinkStatus->recvSlotNIFlag | gRfuLinkStatus->sendSlotUNIFlag))
+ {
+ if (gRfuStatic->commExistFlag)
+ {
+ gRfuStatic->emberCount = 16;
+ gRfuStatic->nullFrameCount = 0;
+ }
+ if (gRfuStatic->emberCount)
+ --gRfuStatic->emberCount;
+ else
+ ++gRfuStatic->nullFrameCount;
+ if (gRfuStatic->emberCount
+ || !(gRfuStatic->nullFrameCount & 0xF))
+ {
+ gRfuFixed->LLFBuffer[0] = 1;
+ gRfuFixed->LLFBuffer[4] = 0xFF;
+ STWI_set_Callback_M(rfu_CB_sendData3);
+ if (r5 == 0)
+ STWI_send_DataTxREQ(gRfuFixed->LLFBuffer, 1);
+ else
+ STWI_send_DataTxAndChangeREQ(gRfuFixed->LLFBuffer, 1);
+ return;
+ }
+ }
+ else
+ {
+ if (!gRfuLinkStatus->LLFReadyFlag)
+ rfu_constructSendLLFrame();
+ if (gRfuLinkStatus->LLFReadyFlag)
+ {
+ STWI_set_Callback_M(rfu_CB_sendData);
+ if (r5 != 0)
+ {
+ STWI_send_DataTxAndChangeREQ(gRfuFixed->LLFBuffer, gRfuStatic->totalPacketSize + 4);
+ return;
+ }
+ STWI_send_DataTxREQ(gRfuFixed->LLFBuffer, gRfuStatic->totalPacketSize + 4);
+ }
+ }
+ if (r5 != 0)
+ {
+ if (gRfuLinkStatus->connMode == 1)
+ {
+ if (gRfuState->callbackS != NULL)
+ gRfuState->callbackS(39);
+ }
+ else
+ {
+ STWI_set_Callback_M(rfu_CB_sendData2);
+ STWI_send_MS_ChangeREQ();
+ }
+ }
+ }
+}
+
+void rfu_CB_sendData(UNUSED u8 r0, u16 r7)
+{
+ u8 r6;
+ struct NIComm *r4;
+
+ if (r7 == 0)
+ {
+ for (r6 = 0; r6 < NELEMS(gRfuSlotStatusNI); ++r6)
+ {
+ if (gRfuSlotStatusUNI[r6]->sub.send.dataReadyFlag)
+ gRfuSlotStatusUNI[r6]->sub.send.dataReadyFlag = 0;
+ r4 = &gRfuSlotStatusNI[r6]->sub.send;
+ if (r4->state == 0x8020)
+ {
+ rfu_STC_releaseFrame(r6, 0, r4);
+ gRfuLinkStatus->sendSlotNIFlag &= ~r4->bmSlot;
+ if (r4->dataType == 1)
+ gRfuLinkStatus->getNameFlag |= 1 << r6;
+ r4->state = 38;
+ }
+ }
+ }
+ gRfuLinkStatus->LLFReadyFlag = 0;
+ rfu_STC_REQ_callback(36, r7);
+}
+
+void rfu_CB_sendData2(UNUSED u8 r0, u16 r1)
+{
+ rfu_STC_REQ_callback(36, r1);
+}
+
+void rfu_CB_sendData3(u8 r0, u16 r1)
+{
+ if (r1 != 0)
+ rfu_STC_REQ_callback(36, r1);
+ else if (r0 == 0xFF)
+ rfu_STC_REQ_callback(0xFF, 0);
+}
+
+void rfu_constructSendLLFrame(void)
+{
+ u32 r8, r5;
+ u8 r6;
+ u8 *sp00;
+ struct RfuSlotStatusNI *r2;
+
+ if (gRfuLinkStatus->connMode != 0xFF
+ && gRfuLinkStatus->sendSlotNIFlag | gRfuLinkStatus->recvSlotNIFlag | gRfuLinkStatus->sendSlotUNIFlag)
+ {
+ gRfuLinkStatus->LLFReadyFlag = 0;
+ r8 = 0;
+ sp00 = (u8 *)&gRfuFixed->LLFBuffer[1];
+ for (r6 = 0; r6 < NELEMS(gRfuSlotStatusUNI); ++r6)
+ {
+ r5 = 0;
+ if (gRfuSlotStatusNI[r6]->sub.send.state & 0x8000)
+ r5 = rfu_STC_NI_constructLLSF(r6, &sp00, &gRfuSlotStatusNI[r6]->sub.send);
+ if (gRfuSlotStatusNI[r6]->sub.recv.state & 0x8000)
+ r5 += rfu_STC_NI_constructLLSF(r6, &sp00, &gRfuSlotStatusNI[r6]->sub.recv);
+ if (gRfuSlotStatusUNI[r6]->sub.send.state == 0x8024)
+ r5 += rfu_STC_UNI_constructLLSF(r6, &sp00);
+ if (r5 != 0)
+ {
+ if (gRfuLinkStatus->connMode == 1)
+ r8 += r5;
+ else
+ r8 |= r5 << (5 * r6 + 8);
+ }
+ }
+ if (r8 != 0)
+ {
+ while ((u32)sp00 & 3)
+ *sp00++ = 0;
+ gRfuFixed->LLFBuffer[0] = r8;
+ if (gRfuLinkStatus->connMode == 0)
+ {
+ u8 *r0 = sp00 - offsetof(struct RfuFixed, LLFBuffer[1]);
+
+ // Does the volatile qualifier make sense?
+ // It's the same as:
+ // asm("":::"memory");
+ r8 = r0 - *(u8 *volatile *)&gRfuFixed;
+ }
+ }
+ gRfuStatic->totalPacketSize = r8;
+ }
+}
+
+u16 rfu_STC_NI_constructLLSF(u8 r10, u8 **r12, struct NIComm *r4)
+{
+ u16 r5;
+ u32 sp00;
+ u8 i;
+ u8 *r2;
+ const u8 *r8 = &_Str_RfuHeader[16 * gRfuLinkStatus->connMode];
+
+ if (r4->state == 0x8022)
+ {
+ while (r4->nowP[r4->phase] >= (const u8 *)r4->src + r4->dataSize)
+ {
+ ++r4->phase;
+ if (r4->phase == 4)
+ r4->phase = 0;
+ }
+ }
+ if (r4->state & 0x40)
+ {
+ r5 = 0;
+ }
+ else if (r4->state == 0x8022)
+ {
+ if (r4->nowP[r4->phase] + r4->payloadSize > (const u8 *)r4->src + r4->dataSize)
+ r5 = (const u8 *)r4->src + r4->dataSize - r4->nowP[r4->phase];
+ else
+ r5 = r4->payloadSize;
+ }
+ else
+ {
+ if (r4->remainSize >= r4->payloadSize)
+ r5 = r4->payloadSize;
+ else
+ r5 = r4->remainSize;
+ }
+ sp00 = (r4->state & 0xF) << r8[3]
+ | r4->ack << r8[4]
+ | r4->phase << r8[5]
+ | r4->n[r4->phase] << r8[6]
+ | r5;
+ if (gRfuLinkStatus->connMode == 1)
+ sp00 |= r4->bmSlot << 18;
+ r2 = (u8 *)&sp00;
+ for (i = 0; i < *r8; ++i)
+ *(*r12)++ = *r2++;
+ if (r5 != 0)
+ {
+ const u8 *sp04 = r4->nowP[r4->phase];
+
+ gRfuFixed->fastCopyPtr(&sp04, r12, r5);
+ }
+ if (r4->state == 0x8022)
+ {
+ ++r4->phase;
+ if (r4->phase == 4)
+ r4->phase = 0;
+ }
+ if (gRfuLinkStatus->connMode == 1)
+ gRfuLinkStatus->LLFReadyFlag = 1;
+ else
+ gRfuLinkStatus->LLFReadyFlag |= 1 << r10;
+ return r5 + *r8;
+}
+
+u16 rfu_STC_UNI_constructLLSF(u8 r8, u8 **r6)
+{
+ const u8 *r5;
+ const u8 *sp04;
+ u32 sp00;
+ u8 *r2;
+ u8 i;
+ struct UNISend *r4 = &gRfuSlotStatusUNI[r8]->sub.send;
+
+ if (!r4->dataReadyFlag || !r4->bmSlot)
+ return 0;
+ r5 = &_Str_RfuHeader[16 * gRfuLinkStatus->connMode];
+ sp00 = (r4->state & 0xF) << r5[3]
+ | r4->payloadSize;
+ if (gRfuLinkStatus->connMode == 1)
+ sp00 |= r4->bmSlot << 18;
+ r2 = (u8 *)&sp00;
+ for (i = 0; i < *r5; ++i)
+ *(*r6)++ = *r2++;
+ sp04 = r4->src;
+ gRfuFixed->fastCopyPtr(&sp04, r6, r4->payloadSize);
+ if (gRfuLinkStatus->connMode == 1)
+ gRfuLinkStatus->LLFReadyFlag = 16;
+ else
+ gRfuLinkStatus->LLFReadyFlag |= 16 << r8;
+ return *r5 + r4->payloadSize;
+}
+
+void rfu_REQ_recvData(void)
+{
+ if (gRfuLinkStatus->connMode != 0xFF)
+ {
+ gRfuStatic->commExistFlag = gRfuLinkStatus->sendSlotNIFlag | gRfuLinkStatus->recvSlotNIFlag | gRfuLinkStatus->sendSlotUNIFlag;
+ gRfuStatic->recvErrorFlag = 0;
+ STWI_set_Callback_M(rfu_CB_recvData);
+ STWI_send_DataRxREQ();
+ }
+}
+
+void rfu_CB_recvData(u8 r9, u16 r7)
+{
+ u8 r6;
+ struct RfuSlotStatusNI *r4;
+ struct NIComm *r5;
+
+ if (r7 == 0 && gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[1])
+ {
+ gRfuStatic->NIEndRecvFlag = 0;
+ if (gRfuLinkStatus->connMode == 1)
+ rfu_STC_PARENT_analyzeRecvPacket();
+ else
+ rfu_STC_CHILD_analyzeRecvPacket();
+ for (r6 = 0; r6 < NELEMS(gRfuSlotStatusNI); ++r6)
+ {
+ r4 = gRfuSlotStatusNI[r6];
+ if (r4->sub.recv.state == 0x8043 && !((gRfuStatic->NIEndRecvFlag >> r6) & 1))
+ {
+ r5 = &r4->sub.recv;
+ if (r5->dataType == 1)
+ gRfuLinkStatus->getNameFlag |= 1 << r6;
+ rfu_STC_releaseFrame(r6, 1, r5);
+ gRfuLinkStatus->recvSlotNIFlag &= ~r5->bmSlot;
+ r4->sub.recv.state = 70;
+ }
+ }
+ if ( gRfuStatic->recvErrorFlag )
+ r7 = gRfuStatic->recvErrorFlag | 0x700;
+ }
+ rfu_STC_REQ_callback(r9, r7);
+}
+
+void rfu_STC_PARENT_analyzeRecvPacket(void)
+{
+ u32 r3;
+ u8 r5;
+ u8 sp[4];
+ u8 *r6;
+
+ r3 = gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket32.data[0] >> 8;
+ for (r5 = 0; r5 < NELEMS(sp); ++r5)
+ {
+ sp[r5] = r3 & 0x1F;
+ r3 >>= 5;
+ if (sp[r5] == 0)
+ gRfuStatic->NIEndRecvFlag |= 1 << r5;
+ }
+ r6 = &gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[8];
+ for (r5 = 0; r5 < NELEMS(sp); ++r5)
+ {
+ if (sp[r5])
+ {
+ u8 *r4 = &sp[r5];
+
+ do
+ {
+ u8 r0 = rfu_STC_analyzeLLSF(r5, r6, *r4);
+
+ r6 += r0;
+ *r4 -= r0;
+ } while (!(*r4 & 0x80) && (*r4));
+ }
+ }
+}
+
+void rfu_STC_CHILD_analyzeRecvPacket(void)
+{
+ u16 r4;
+ u8 *r5;
+ u16 r0;
+
+ r4 = *(u16 *)&gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[4] & 0x7F;
+ r5 = &gRfuFixed->STWIBuffer->rxPacketAlloc.rfuPacket8.data[8];
+ if (r4 == 0)
+ gRfuStatic->NIEndRecvFlag = 15;
+ do
+ {
+ if (r4 == 0)
+ break;
+ r0 = rfu_STC_analyzeLLSF(0, r5, r4);
+ r5 += r0;
+ r4 -= r0;
+ } while (!(r4 & 0x8000));
+}