mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-10-02 05:47:11 -05:00
Starting wireless multiboot draft
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include <tonc.h>
|
||||
#include "../../../lib/LinkRawWireless.hpp"
|
||||
#include "../../../lib/LinkWirelessMultiboot.hpp"
|
||||
#include "../../_lib/interrupt.h"
|
||||
#include "scenes/MultibootScene.h"
|
||||
#include "utils/SceneUtils.h"
|
||||
@@ -11,7 +11,7 @@ static std::shared_ptr<GBAEngine> engine{new GBAEngine()};
|
||||
static std::unique_ptr<MultibootScene> multibootScene{
|
||||
new MultibootScene(engine)};
|
||||
|
||||
LinkRawWireless* linkRawWireless = new LinkRawWireless();
|
||||
LinkWirelessMultiboot* linkWirelessMultiboot = new LinkWirelessMultiboot();
|
||||
|
||||
int main() {
|
||||
setUpInterrupts();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "../../../../lib/LinkRawWireless.hpp"
|
||||
#include "../../../../lib/LinkWirelessMultiboot.hpp"
|
||||
#include "utils/InputHandler.h"
|
||||
#include "utils/SceneUtils.h"
|
||||
|
||||
@@ -123,7 +123,11 @@ void MultibootScene::load() {
|
||||
SCENE_init();
|
||||
BACKGROUND_enable(true, false, false, false);
|
||||
|
||||
linkRawWireless->logger = [](std::string string) {
|
||||
linkWirelessMultiboot->logger = [](std::string string) {
|
||||
// if (useVerboseLog) // TODO: RESTORE
|
||||
log(string);
|
||||
};
|
||||
linkWirelessMultiboot->link->logger = [](std::string string) {
|
||||
if (useVerboseLog)
|
||||
log(string);
|
||||
};
|
||||
@@ -180,7 +184,11 @@ void MultibootScene::processButtons() {
|
||||
toggleLogLevel();
|
||||
|
||||
if (aHandler->hasBeenPressedNow()) {
|
||||
// TODO: IMPLEMENT
|
||||
u32 fileLength;
|
||||
const void* romToSend = gbfs_get_obj(fs, ROM_FILE_NAME, &fileLength);
|
||||
|
||||
linkWirelessMultiboot->sendRom(romToSend, fileLength,
|
||||
[]() { return false; });
|
||||
print();
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +116,6 @@ class LinkSPI {
|
||||
setInterruptsOff();
|
||||
}
|
||||
|
||||
enableTransfer();
|
||||
|
||||
while (isMaster() && waitMode && !isSlaveReady())
|
||||
if (cancel()) {
|
||||
disableTransfer();
|
||||
@@ -126,6 +124,7 @@ class LinkSPI {
|
||||
return LINK_SPI_NO_DATA;
|
||||
}
|
||||
|
||||
enableTransfer(); // TODO: TEST THIS (moved)
|
||||
startTransfer();
|
||||
|
||||
if (_async)
|
||||
|
||||
@@ -32,9 +32,38 @@ static volatile char LINK_WIRELESS_MULTIBOOT_VERSION[] =
|
||||
"LinkWirelessMultiboot/v6.2.0";
|
||||
|
||||
class LinkWirelessMultiboot {
|
||||
typedef void (*Logger)(std::string);
|
||||
|
||||
public:
|
||||
Logger logger = [](std::string str) {};
|
||||
enum Result { SUCCESS, INVALID_SIZE, CANCELED, FAILURE };
|
||||
|
||||
struct ServerSDKHeader {
|
||||
unsigned int payloadSize : 7;
|
||||
unsigned int _unused_ : 2;
|
||||
unsigned int phase : 2;
|
||||
unsigned int n : 2;
|
||||
unsigned int isACK : 1;
|
||||
unsigned int slotState : 4;
|
||||
unsigned int targetSlots : 4;
|
||||
};
|
||||
union ServerSDKHeaderSerializer {
|
||||
ServerSDKHeader asStruct;
|
||||
u32 asInt;
|
||||
};
|
||||
|
||||
struct ClientSDKHeader {
|
||||
unsigned int payloadSize : 5;
|
||||
unsigned int phase : 2;
|
||||
unsigned int n : 2;
|
||||
unsigned int isACK : 1;
|
||||
unsigned int slotState : 4;
|
||||
};
|
||||
union ClientSDKHeaderSerializer {
|
||||
ClientSDKHeader asStruct;
|
||||
u16 asInt;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
Result sendRom(const void* rom, u32 romSize, F cancel) {
|
||||
// if (romSize < LINK_WIRELESS_MULTIBOOT_MIN_ROM_SIZE)
|
||||
@@ -44,12 +73,170 @@ class LinkWirelessMultiboot {
|
||||
// if ((romSize % 0x10) != 0)
|
||||
// return INVALID_SIZE;
|
||||
|
||||
// TODO: IMPLEMENT
|
||||
bool success = true;
|
||||
success = link->activate();
|
||||
if (!success) {
|
||||
logger("cannot activate");
|
||||
return FAILURE;
|
||||
}
|
||||
logger("activated");
|
||||
|
||||
success = link->sendCommand(LINK_RAW_WIRELESS_COMMAND_SETUP,
|
||||
std::vector<u32>{0x003F0120})
|
||||
.success; // TODO: IMPLEMENT SETUP
|
||||
if (!success) {
|
||||
logger("setup failed");
|
||||
return FAILURE;
|
||||
}
|
||||
logger("setup ok");
|
||||
|
||||
success = link->broadcast("Multi", "Test", 0b1111111111111111);
|
||||
if (!success) {
|
||||
logger("broadcast failed");
|
||||
return FAILURE;
|
||||
}
|
||||
logger("broadcast set");
|
||||
|
||||
success = link->startHost();
|
||||
if (!success) {
|
||||
logger("start host failed");
|
||||
return FAILURE;
|
||||
}
|
||||
logger("host started");
|
||||
|
||||
LinkRawWireless::AcceptConnectionsResponse acceptResponse;
|
||||
while (link->playerCount() == 1) {
|
||||
link->acceptConnections(acceptResponse);
|
||||
}
|
||||
|
||||
logger("connected!");
|
||||
linkRawWireless->wait(228 * 20); // ~300ms
|
||||
|
||||
bool hasData = false;
|
||||
LinkRawWireless::ReceiveDataResponse response;
|
||||
while (!hasData) {
|
||||
if (!sendAndExpectData(std::vector<u32>{}, 1, response))
|
||||
return FAILURE;
|
||||
hasData = response.data.size() > 0;
|
||||
}
|
||||
|
||||
logger("data received");
|
||||
ClientSDKHeader clientHeader = parseClientHeader(response.data[0]);
|
||||
logger("client size: " + std::to_string(clientHeader.payloadSize));
|
||||
logger("n: " + std::to_string(clientHeader.n));
|
||||
logger("phase: " + std::to_string(clientHeader.phase));
|
||||
logger("ack: " + std::to_string(clientHeader.isACK));
|
||||
logger("slotState:" + std::to_string(clientHeader.slotState));
|
||||
|
||||
logger("sending ACK");
|
||||
firstack:
|
||||
ServerSDKHeader serverHeader;
|
||||
serverHeader = createACKFor(clientHeader);
|
||||
u32 sndHeader = serializeServerHeader(serverHeader);
|
||||
|
||||
if (!sendAndExpectData(std::vector<u32>{sndHeader}, 3, response))
|
||||
return FAILURE;
|
||||
|
||||
if (response.data.size() == 0) {
|
||||
goto firstack;
|
||||
}
|
||||
clientHeader = parseClientHeader(response.data[0]);
|
||||
if (clientHeader.n == 1)
|
||||
goto firstack;
|
||||
|
||||
if (clientHeader.n == 2 && clientHeader.slotState == 1) {
|
||||
logger("N IS NOW 2, slotstate = 1");
|
||||
} else {
|
||||
logger("Error: weird packet");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
secondack:
|
||||
serverHeader = createACKFor(clientHeader);
|
||||
sndHeader = serializeServerHeader(serverHeader);
|
||||
if (!sendAndExpectData(std::vector<u32>{sndHeader}, 3, response))
|
||||
return FAILURE;
|
||||
|
||||
if (response.data.size() == 0) {
|
||||
goto secondack;
|
||||
}
|
||||
clientHeader = parseClientHeader(response.data[0]);
|
||||
if (clientHeader.n == 2 && clientHeader.slotState == 1)
|
||||
goto secondack;
|
||||
|
||||
if (clientHeader.n == 1 && clientHeader.slotState == 2) {
|
||||
logger("NI STARTED");
|
||||
} else {
|
||||
logger("NI DIDN'T START");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
while (clientHeader.slotState > 0) {
|
||||
link->wait(228);
|
||||
serverHeader = createACKFor(clientHeader);
|
||||
sndHeader = serializeServerHeader(serverHeader);
|
||||
if (!sendAndExpectData(std::vector<u32>{sndHeader}, 3, response))
|
||||
return FAILURE;
|
||||
|
||||
clientHeader = parseClientHeader(response.data[0]);
|
||||
}
|
||||
|
||||
logger("slotState IS NOW 0");
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
LinkRawWireless* link = new LinkRawWireless();
|
||||
|
||||
ClientSDKHeader lastACK;
|
||||
|
||||
private:
|
||||
bool sendAndExpectData(std::vector<u32> data,
|
||||
u32 _bytes,
|
||||
LinkRawWireless::ReceiveDataResponse& response) {
|
||||
LinkRawWireless::RemoteCommand remoteCommand;
|
||||
bool success = false;
|
||||
success = link->sendDataAndWait(data, remoteCommand, _bytes);
|
||||
if (!success) {
|
||||
logger("senddatawait no");
|
||||
return false;
|
||||
}
|
||||
if (remoteCommand.commandId != 0x28) {
|
||||
logger("expected response 0x28");
|
||||
logger("but got " + link->toHex(remoteCommand.commandId));
|
||||
return false;
|
||||
}
|
||||
success = link->receiveData(response);
|
||||
if (!success) {
|
||||
logger("receive data failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ServerSDKHeader createACKFor(ClientSDKHeader clientHeader) {
|
||||
ServerSDKHeader serverHeader;
|
||||
serverHeader.isACK = 1;
|
||||
serverHeader.targetSlots = 0b0001; // TODO: Implement
|
||||
serverHeader.payloadSize = 0;
|
||||
serverHeader.n = clientHeader.n;
|
||||
serverHeader.phase = clientHeader.phase;
|
||||
serverHeader.slotState = clientHeader.slotState;
|
||||
|
||||
return serverHeader;
|
||||
}
|
||||
|
||||
ClientSDKHeader parseClientHeader(u32 clientHeaderInt) {
|
||||
ClientSDKHeaderSerializer clientSerializer;
|
||||
clientSerializer.asInt = clientHeaderInt;
|
||||
return clientSerializer.asStruct;
|
||||
}
|
||||
|
||||
u32 serializeServerHeader(ServerSDKHeader serverHeader) {
|
||||
ServerSDKHeaderSerializer serverSerializer;
|
||||
serverSerializer.asStruct = serverHeader;
|
||||
return serverSerializer.asInt;
|
||||
}
|
||||
};
|
||||
|
||||
extern LinkWirelessMultiboot* linkWirelessMultiboot;
|
||||
|
||||
Reference in New Issue
Block a user