Moving most of the file transfer logic to LinkWirelessOpenSDK

This commit is contained in:
Rodrigo Alfonso
2025-01-02 05:23:35 -03:00
parent 283dd81b73
commit 28b0ecda64
2 changed files with 123 additions and 88 deletions

View File

@@ -57,6 +57,13 @@ static volatile char LINK_WIRELESS_MULTIBOOT_VERSION[] =
if ((lastResult = CALL) != SUCCESS) { \
return finish(lastResult); \
}
#define LINK_WIRELESS_MULTIBOOT_TRY_SUB(CALL) \
LINK_WIRELESS_MULTIBOOT_BARRIER; \
if ((lastResult = CALL) != SUCCESS) { \
return lastResult; \
}
#define _LWMNI_ __attribute__((noinline))
#ifdef LINK_WIRELESS_MULTIBOOT_ENABLE_LOGGING
#include <string>
@@ -147,13 +154,13 @@ class LinkWirelessMultiboot {
* \warning Blocks the system until completion or cancellation.
*/
template <typename C>
Result sendRom(const u8* rom,
u32 romSize,
const char* gameName,
const char* userName,
const u16 gameId,
u8 players,
C listener) {
_LWMNI_ Result sendRom(const u8* rom,
u32 romSize,
const char* gameName,
const char* userName,
const u16 gameId,
u8 players,
C listener) {
if (romSize < LINK_WIRELESS_MULTIBOOT_MIN_ROM_SIZE)
return INVALID_SIZE;
if (romSize > LINK_WIRELESS_MULTIBOOT_MAX_ROM_SIZE)
@@ -204,7 +211,7 @@ class LinkWirelessMultiboot {
volatile Result lastResult;
ClientHeader lastValidHeader;
Result activate() {
_LWMNI_ Result activate() {
if (!linkRawWireless->activate()) {
_LWMLOG_("! adapter not detected");
return ADAPTER_NOT_DETECTED;
@@ -214,10 +221,10 @@ class LinkWirelessMultiboot {
return SUCCESS;
}
Result initialize(const char* gameName,
const char* userName,
const u16 gameId,
u8 players) {
_LWMNI_ Result initialize(const char* gameName,
const char* userName,
const u16 gameId,
u8 players) {
if (!linkRawWireless->setup(players, SETUP_TX, SETUP_WAIT_TIMEOUT,
SETUP_MAGIC)) {
_LWMLOG_("! setup failed");
@@ -242,7 +249,7 @@ class LinkWirelessMultiboot {
}
template <typename C>
Result waitForClients(u8 players, C listener) {
_LWMNI_ Result waitForClients(u8 players, C listener) {
LinkRawWireless::AcceptConnectionsResponse acceptResponse;
u32 currentPlayers = 1;
@@ -261,7 +268,8 @@ class LinkWirelessMultiboot {
acceptResponse
.connectedClients[acceptResponse.connectedClientsSize - 1]
.clientNumber;
LINK_WIRELESS_MULTIBOOT_TRY(handshakeClient(lastClientNumber, listener))
LINK_WIRELESS_MULTIBOOT_TRY_SUB(
handshakeClient(lastClientNumber, listener))
}
}
@@ -271,12 +279,12 @@ class LinkWirelessMultiboot {
}
template <typename C>
Result handshakeClient(u8 clientNumber, C listener) {
ClientPacket handshakePackets[2];
_LWMNI_ Result handshakeClient(u8 clientNumber, C listener) {
ClientPacket handshakePackets[2] = {ClientPacket{}, ClientPacket{}};
volatile bool hasReceivedName = false;
_LWMLOG_("new client: " + std::to_string(clientNumber));
LINK_WIRELESS_MULTIBOOT_TRY(exchangeData(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeData(
clientNumber,
[this](LinkRawWireless::ReceiveDataResponse& response) {
return sendAndExpectData(toArray(), 0, 1, response);
@@ -285,7 +293,7 @@ class LinkWirelessMultiboot {
// (initial client packet received)
_LWMLOG_("handshake (1/2)...");
LINK_WIRELESS_MULTIBOOT_TRY(exchangeACKData(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeACKData(
clientNumber,
[](ClientPacket packet) {
auto header = packet.header;
@@ -295,7 +303,7 @@ class LinkWirelessMultiboot {
// (n = 2, commState = 1)
_LWMLOG_("handshake (2/2)...");
LINK_WIRELESS_MULTIBOOT_TRY(exchangeACKData(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeACKData(
clientNumber,
[&handshakePackets](ClientPacket packet) {
auto header = packet.header;
@@ -309,7 +317,7 @@ class LinkWirelessMultiboot {
// (n = 1, commState = 2)
_LWMLOG_("receiving name...");
LINK_WIRELESS_MULTIBOOT_TRY(exchangeACKData(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeACKData(
clientNumber,
[this, &handshakePackets, &hasReceivedName](ClientPacket packet) {
auto header = packet.header;
@@ -344,7 +352,8 @@ class LinkWirelessMultiboot {
return CANCELED;
LinkRawWireless::ReceiveDataResponse response;
LINK_WIRELESS_MULTIBOOT_TRY(sendAndExpectData(toArray(), 0, 1, response))
LINK_WIRELESS_MULTIBOOT_TRY_SUB(
sendAndExpectData(toArray(), 0, 1, response))
auto childrenData = linkWirelessOpenSDK->getChildrenData(response);
hasFinished = childrenData.responses[clientNumber].packetsSize == 0;
}
@@ -356,9 +365,9 @@ class LinkWirelessMultiboot {
}
template <typename C>
Result sendRomStartCommand(C listener) {
_LWMNI_ Result sendRomStartCommand(C listener) {
for (u32 i = 0; i < progress.connectedClients; i++) {
LINK_WIRELESS_MULTIBOOT_TRY(exchangeNewData(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeNewData(
i,
linkWirelessOpenSDK->createServerBuffer(
CMD_START, CMD_START_SIZE, {1, 0, CommState::STARTING}, 1 << i),
@@ -369,9 +378,7 @@ class LinkWirelessMultiboot {
}
template <typename C>
Result sendRomBytes(const u8* rom, u32 romSize, C listener) {
LinkWirelessOpenSDK::MultiTransfer<MAX_INFLIGHT_PACKETS> multiTransfer;
_LWMNI_ Result sendRomBytes(const u8* rom, u32 romSize, C listener) {
u8 firstPagePatch[LinkWirelessOpenSDK::MAX_PAYLOAD_SERVER];
for (u32 i = 0; i < LinkWirelessOpenSDK::MAX_PAYLOAD_SERVER; i++) {
firstPagePatch[i] =
@@ -380,37 +387,24 @@ class LinkWirelessMultiboot {
? ROM_HEADER_PATCH[i - ROM_HEADER_PATCH_OFFSET]
: rom[i];
}
progress.percentage = 0;
u32 minClient = 0;
while (multiTransfer.minClientTransferredBytes(progress.connectedClients,
&minClient) < romSize) {
LinkWirelessOpenSDK::MultiTransfer<MAX_INFLIGHT_PACKETS> multiTransfer(
linkWirelessOpenSDK, romSize, progress.connectedClients);
while (!multiTransfer.hasFinished()) {
if (listener(progress))
return CANCELED;
LINK_WIRELESS_MULTIBOOT_TRY(ensureAllClientsAreStillAlive())
LINK_WIRELESS_MULTIBOOT_TRY_SUB(ensureAllClientsAreStillAlive())
u32 cursor = multiTransfer.findMinCursor(progress.connectedClients);
u32 offset = cursor * LinkWirelessOpenSDK::MAX_PAYLOAD_SERVER;
auto sequence = Sequence::fromPacketId(cursor);
const u8* bufferToSend = cursor == 0 ? (const u8*)firstPagePatch : rom;
auto sendBuffer = linkWirelessOpenSDK->createServerBuffer(
bufferToSend, romSize, sequence, 0b1111, offset);
for (u32 i = 0; i < progress.connectedClients; i++)
multiTransfer.transfers[i].addIfNeeded(cursor);
auto sendBuffer = multiTransfer.createNextSendBuffer(
multiTransfer.getCursor() == 0 ? (const u8*)firstPagePatch : rom);
LinkRawWireless::ReceiveDataResponse response;
LINK_WIRELESS_MULTIBOOT_TRY(sendAndExpectData(sendBuffer, response))
LINK_WIRELESS_MULTIBOOT_TRY_SUB(sendAndExpectData(sendBuffer, response))
auto childrenData = linkWirelessOpenSDK->getChildrenData(response);
multiTransfer.updateACKs(childrenData, progress.connectedClients);
auto transferredBytes =
multiTransfer.minClientTransferredBytes(progress.connectedClients);
u32 newPercentage = Link::_min(transferredBytes * 100 / romSize, 100);
u32 newPercentage = multiTransfer.processResponse(response);
if (newPercentage != progress.percentage) {
progress.percentage = newPercentage;
_LWMLOG_("-> " + std::to_string(newPercentage));
@@ -421,10 +415,10 @@ class LinkWirelessMultiboot {
}
template <typename C>
Result confirm(C listener) {
_LWMNI_ Result confirm(C listener) {
_LWMLOG_("confirming (1/2)...");
for (u32 i = 0; i < progress.connectedClients; i++) {
LINK_WIRELESS_MULTIBOOT_TRY(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(
exchangeNewData(i,
linkWirelessOpenSDK->createServerBuffer(
{}, 0, {0, 0, CommState::ENDING}, 1 << i),
@@ -436,7 +430,7 @@ class LinkWirelessMultiboot {
_LWMLOG_("confirming (2/2)...");
for (u32 i = 0; i < progress.connectedClients; i++) {
LinkRawWireless::ReceiveDataResponse response;
LINK_WIRELESS_MULTIBOOT_TRY(
LINK_WIRELESS_MULTIBOOT_TRY_SUB(
sendAndExpectData(linkWirelessOpenSDK->createServerBuffer(
{}, 0, {1, 0, CommState::OFF}, 1 << i),
response))
@@ -446,8 +440,10 @@ class LinkWirelessMultiboot {
}
template <typename C>
Result exchangeNewData(u8 clientNumber, SendBuffer sendBuffer, C listener) {
LINK_WIRELESS_MULTIBOOT_TRY(exchangeData(
_LWMNI_ Result exchangeNewData(u8 clientNumber,
SendBuffer sendBuffer,
C listener) {
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeData(
clientNumber,
[this, &sendBuffer](LinkRawWireless::ReceiveDataResponse& response) {
return sendAndExpectData(sendBuffer, response);
@@ -463,8 +459,10 @@ class LinkWirelessMultiboot {
}
template <typename V, typename C>
Result exchangeACKData(u8 clientNumber, V validatePacket, C listener) {
LINK_WIRELESS_MULTIBOOT_TRY(exchangeData(
_LWMNI_ Result exchangeACKData(u8 clientNumber,
V validatePacket,
C listener) {
LINK_WIRELESS_MULTIBOOT_TRY_SUB(exchangeData(
clientNumber,
[this, clientNumber](LinkRawWireless::ReceiveDataResponse& response) {
return sendAndExpectData(linkWirelessOpenSDK->createServerACKBuffer(
@@ -477,17 +475,15 @@ class LinkWirelessMultiboot {
}
template <typename F, typename V, typename C>
Result exchangeData(u8 clientNumber,
F sendAction,
V validatePacket,
C listener) {
_LWMNI_ Result
exchangeData(u8 clientNumber, F sendAction, V validatePacket, C listener) {
volatile bool hasFinished = false;
while (!hasFinished) {
if (listener(progress))
return CANCELED;
LinkRawWireless::ReceiveDataResponse response;
LINK_WIRELESS_MULTIBOOT_TRY(sendAction(response))
LINK_WIRELESS_MULTIBOOT_TRY_SUB(sendAction(response))
auto childrenData = linkWirelessOpenSDK->getChildrenData(response);
for (u32 i = 0; i < childrenData.responses[clientNumber].packetsSize;
@@ -505,13 +501,14 @@ class LinkWirelessMultiboot {
return SUCCESS;
}
Result sendAndExpectData(SendBuffer sendBuffer,
LinkRawWireless::ReceiveDataResponse& response) {
_LWMNI_ Result
sendAndExpectData(SendBuffer sendBuffer,
LinkRawWireless::ReceiveDataResponse& response) {
return sendAndExpectData(sendBuffer.data, sendBuffer.dataSize,
sendBuffer.totalByteCount, response);
}
Result sendAndExpectData(
_LWMNI_ Result sendAndExpectData(
std::array<u32, LINK_RAW_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH> data,
u32 dataSize,
u32 _bytes,
@@ -522,23 +519,17 @@ class LinkWirelessMultiboot {
success =
linkRawWireless->sendDataAndWait(data, dataSize, remoteCommand, _bytes);
LINK_WIRELESS_MULTIBOOT_BARRIER;
if (!success) {
_LWMLOG_("! sendDataAndWait failed");
return FAILURE;
}
LINK_WIRELESS_MULTIBOOT_BARRIER;
if (remoteCommand.commandId != 0x28) {
_LWMLOG_("! expected EVENT 0x28");
_LWMLOG_("! but got " + toHex(remoteCommand.commandId));
return FAILURE;
}
LINK_WIRELESS_MULTIBOOT_BARRIER;
if (remoteCommand.paramsSize > 0) {
u8 expectedActiveChildren = 0;
for (u32 i = 0; i < progress.connectedClients; i++)
@@ -554,12 +545,8 @@ class LinkWirelessMultiboot {
}
}
LINK_WIRELESS_MULTIBOOT_BARRIER;
success = linkRawWireless->receiveData(response);
LINK_WIRELESS_MULTIBOOT_BARRIER;
if (!success) {
_LWMLOG_("! receiveData failed");
return FAILURE;
@@ -568,7 +555,7 @@ class LinkWirelessMultiboot {
return SUCCESS;
}
Result ensureAllClientsAreStillAlive() {
_LWMNI_ Result ensureAllClientsAreStillAlive() {
LinkRawWireless::SlotStatusResponse slotStatusResponse;
if (!linkRawWireless->getSlotStatus(slotStatusResponse))
return FAILURE;
@@ -579,18 +566,20 @@ class LinkWirelessMultiboot {
return SUCCESS;
}
Result finish(Result result) {
_LWMNI_ Result finish(Result result) {
linkRawWireless->bye();
linkRawWireless->deactivate();
resetState();
return result;
}
void resetState() {
_LWMNI_ void resetState() {
progress.state = STOPPED;
progress.connectedClients = 0;
progress.percentage = 0;
progress.ready = &readyFlag;
readyFlag = false;
lastValidHeader = ClientHeader{};
}
#ifdef LINK_WIRELESS_MULTIBOOT_ENABLE_LOGGING
@@ -613,6 +602,7 @@ class LinkWirelessMultiboot {
extern LinkWirelessMultiboot* linkWirelessMultiboot;
#undef _LWMNI_
#undef _LWMLOG_
#endif // LINK_WIRELESS_MULTIBOOT_H

View File

@@ -419,7 +419,6 @@ class LinkWirelessOpenSDK {
return serverSerializer.asInt & HEADER_MASK_SERVER;
}
public:
template <u32 MaxInflightPackets>
struct Transfer {
private:
@@ -430,7 +429,7 @@ class LinkWirelessOpenSDK {
};
struct PendingTransferList {
std::array<PendingTransfer, MaxInflightPackets> transfers;
std::array<PendingTransfer, MaxInflightPackets> transfers = {};
PendingTransfer* max(bool ack = false) {
int maxCursor = -1;
@@ -554,13 +553,62 @@ class LinkWirelessOpenSDK {
SequenceNumber sequence() { return SequenceNumber::fromPacketId(cursor); }
};
public:
template <u32 MaxInflightPackets>
struct MultiTransfer {
class MultiTransfer {
public:
explicit MultiTransfer(LinkWirelessOpenSDK* linkWirelessOpenSDK,
u32 fileSize,
u32 connectedClients) {
this->linkWirelessOpenSDK = linkWirelessOpenSDK;
this->fileSize = fileSize;
this->connectedClients = connectedClients;
this->transfers = {};
}
bool hasFinished() { return finished; }
u32 getCursor() { return cursor; }
SendBuffer<ServerSDKHeader> createNextSendBuffer(const u8* fileBytes) {
if (finished)
return SendBuffer<ServerSDKHeader>{};
u32 offset = cursor * LinkWirelessOpenSDK::MAX_PAYLOAD_SERVER;
auto sequence = SequenceNumber::fromPacketId(cursor);
auto sendBuffer = linkWirelessOpenSDK->createServerBuffer(
fileBytes, fileSize, sequence, 0b1111, offset);
for (u32 i = 0; i < connectedClients; i++)
transfers[i].addIfNeeded(cursor);
return sendBuffer;
}
u32 processResponse(LinkRawWireless::ReceiveDataResponse response) {
if (finished)
return 100;
auto childrenData = linkWirelessOpenSDK->getChildrenData(response);
updateACKs(childrenData);
auto transferredBytes = minClientTransferredBytes();
finished = transferredBytes >= fileSize;
cursor = findMinCursor();
return Link::_min(transferredBytes * 100 / fileSize, 100);
}
private:
std::array<Transfer<MaxInflightPackets>, LINK_RAW_WIRELESS_MAX_PLAYERS - 1>
transfers;
public:
void updateACKs(ChildrenData childrenData, u32 connectedClients) {
LinkWirelessOpenSDK* linkWirelessOpenSDK;
u32 fileSize;
u32 connectedClients;
bool finished = false;
u32 cursor = 0;
void updateACKs(ChildrenData childrenData) {
for (u32 i = 0; i < connectedClients; i++) {
for (u32 j = 0; j < childrenData.responses[i].packetsSize; j++) {
auto header = childrenData.responses[i].packets[j].header;
@@ -575,14 +623,11 @@ class LinkWirelessOpenSDK {
}
}
u32 minClientTransferredBytes(u32 connectedClients, u32* minClient = NULL) {
auto currentMinClient = findMinClient(connectedClients);
if (minClient != NULL)
*minClient = currentMinClient;
return transfers[currentMinClient].transferred();
u32 minClientTransferredBytes() {
return transfers[findMinClient()].transferred();
}
u32 findMinClient(u32 connectedClients) {
u32 findMinClient() {
u32 minTransferredBytes = 0xffffffff;
u32 minClient = 0;
@@ -597,7 +642,7 @@ class LinkWirelessOpenSDK {
return minClient;
}
u32 findMinCursor(u32 connectedClients) {
u32 findMinCursor() {
u32 minNextCursor = 0xffffffff;
bool canSendInflightPackets = true;