Implementing receiveAsyncCommandSIO8

This commit is contained in:
Rodrigo Alfonso
2024-08-12 05:46:50 -03:00
parent 7fe1c9f13a
commit c5abe13afd

View File

@@ -176,7 +176,10 @@ class LinkMobile {
// TODO: IMPLEMENT
mgbalog("sio32");
} else {
updateAsyncCommandSIO8(newData);
if (asyncCommand.direction == AsyncCommand::Direction::SENDING)
sendAsyncCommandSIO8(newData);
else
receiveAsyncCommandSIO8(newData);
}
if (asyncCommand.state == AsyncCommand::State::COMPLETED) {
@@ -260,8 +263,14 @@ class LinkMobile {
volatile u32 transferred; // (in SIO32: words; in SIO8: bytes)
Command cmd;
volatile Direction direction;
volatile u16 expectedChecksum;
volatile bool isWaiting;
volatile bool isActive = false;
void fail(CommandResult result) {
result = CommandResult::NOT_WAITING;
state = AsyncCommand::State::COMPLETED;
}
};
static constexpr u32 PREAMBLE_SIZE =
@@ -397,12 +406,22 @@ class LinkMobile {
while (asyncCommand.isActive)
;
if (asyncCommand.result != CommandResult::SUCCESS) {
mgbalog("NOT SUCCESS %d", asyncCommand.result);
mgbalog("NOT SUCCESS SEND %d", asyncCommand.result);
response.result = asyncCommand.result;
return response;
}
response = receiveCommand();
receiveCommandAsync();
while (asyncCommand.isActive)
;
if (asyncCommand.result != CommandResult::SUCCESS) {
mgbalog("NOT SUCCESS RESPONSE %d", asyncCommand.result);
response.result = asyncCommand.result;
return response;
}
response.result = asyncCommand.result;
response.command = asyncCommand.cmd;
auto remoteCommand = response.command.packetHeader.commandId;
if (remoteCommand == COMMAND_ERROR_STATUS) {
if (response.command.packetHeader.dataSizeL != 2 ||
@@ -424,59 +443,6 @@ class LinkMobile {
return response;
}
CommandResponse receiveCommand() {
CommandResponse response;
u8* responseBytes = (u8*)&response.command;
// Magic Bytes
if (waitForMeaningfulByte() != COMMAND_MAGIC_VALUE1) {
response.result = CommandResult::INVALID_MAGIC_BYTES;
return response;
}
if (transfer(GBA_WAITING) != COMMAND_MAGIC_VALUE2) {
response.result = CommandResult::INVALID_MAGIC_BYTES;
return response;
}
// Packet Header
for (u32 i = 2; i < PREAMBLE_SIZE; i++)
responseBytes[i] = transfer(GBA_WAITING);
responseBytes += PREAMBLE_SIZE;
if (response.command.packetHeader._unusedDataSizeH_ != 0) {
response.result = CommandResult::WEIRD_DATA_SIZE;
return response;
}
// Data
for (u32 i = 0; i < response.command.packetHeader.dataSizeL; i++)
responseBytes[i] = transfer(GBA_WAITING);
responseBytes += LINK_MOBILE_MAX_COMMAND_TRANSFER_LENGTH;
// Packet Checksum
for (u32 i = 0; i < CHECKSUM_SIZE; i++)
responseBytes[i] = transfer(GBA_WAITING);
u32 rChecksum = response.command.packetHeader.sum();
for (u32 i = 0; i < response.command.packetHeader.dataSizeL; i++)
rChecksum += response.command.packetData.bytes[i];
if (msB16(rChecksum) != response.command.packetChecksum.checksumH ||
lsB16(rChecksum) != response.command.packetChecksum.checksumL) {
response.result = CommandResult::WRONG_CHECKSUM;
return response;
}
// Acknowledgement Signal
auto ackResult =
acknowledge(response.command.packetHeader.commandId ^ OR_VALUE, 0);
if (ackResult != SUCCESS) {
response.result = ackResult;
return response;
}
response.result = CommandResult::SUCCESS;
return response;
}
bool sendCommandAsync(Command command) { // (irq only)
if (asyncCommand.isActive /* || isSendingSyncCommand*/)
return false;
@@ -488,6 +454,7 @@ class LinkMobile {
asyncCommand.transferred = 0;
asyncCommand.cmd = command;
asyncCommand.direction = AsyncCommand::Direction::SENDING;
asyncCommand.expectedChecksum = 0;
asyncCommand.isWaiting = false;
asyncCommand.isActive = true;
@@ -502,20 +469,37 @@ class LinkMobile {
return true;
}
void updateAsyncCommandSIO8(u32 newData) { // (irq only)
bool receiveCommandAsync() { // (irq only)
if (asyncCommand.isActive /* || isSendingSyncCommand*/)
return false;
mgbalog("Receiving");
asyncCommand.state = AsyncCommand::State::PENDING;
asyncCommand.result = CommandResult::PENDING;
asyncCommand.transferred = 0;
asyncCommand.cmd = Command{};
asyncCommand.direction = AsyncCommand::Direction::RECEIVING;
asyncCommand.expectedChecksum = 0;
asyncCommand.isWaiting = false;
asyncCommand.isActive = true;
transferAsync(GBA_WAITING);
return true;
}
void sendAsyncCommandSIO8(u32 newData) { // (irq only)
const u8* commandBytes = (const u8*)&asyncCommand.cmd;
u32 mainSize = PREAMBLE_SIZE + asyncCommand.cmd.packetHeader.dataSizeL;
bool isAcknowledgement =
asyncCommand.transferred >= mainSize + CHECKSUM_SIZE + 1;
if (!isAcknowledgement && newData != ADAPTER_WAITING) {
asyncCommand.result = CommandResult::NOT_WAITING;
asyncCommand.state = AsyncCommand::State::COMPLETED;
return;
}
if (!isAcknowledgement && newData != ADAPTER_WAITING)
return asyncCommand.fail(CommandResult::NOT_WAITING);
if (asyncCommand.transferred < mainSize) {
// Magic Bytes + Packet Header + Data
// Magic Bytes + Packet Header + Packet Data
transferAsync(commandBytes[asyncCommand.transferred]);
asyncCommand.transferred++;
} else if (asyncCommand.transferred < mainSize + CHECKSUM_SIZE) {
@@ -529,42 +513,93 @@ class LinkMobile {
asyncCommand.transferred++;
} else if (asyncCommand.transferred == mainSize + CHECKSUM_SIZE + 1) {
// Acknowledgement Signal (2)
if (!isSupportedAdapter(newData)) {
asyncCommand.result = CommandResult::INVALID_DEVICE_ID;
asyncCommand.state = AsyncCommand::State::COMPLETED;
return;
}
if (!isSupportedAdapter(newData))
return asyncCommand.fail(CommandResult::INVALID_DEVICE_ID);
transferAsync(0);
asyncCommand.transferred++;
} else if (asyncCommand.transferred == mainSize + CHECKSUM_SIZE + 2) {
// Acknowledgement Signal (3)
if (newData != (asyncCommand.cmd.packetHeader.commandId ^ OR_VALUE)) {
asyncCommand.result = CommandResult::INVALID_COMMAND_ACK;
asyncCommand.state = AsyncCommand::State::COMPLETED;
return;
}
if (newData != (asyncCommand.cmd.packetHeader.commandId ^ OR_VALUE))
return asyncCommand.fail(CommandResult::INVALID_COMMAND_ACK);
asyncCommand.result = CommandResult::SUCCESS;
asyncCommand.state = AsyncCommand::State::COMPLETED;
} else {
mgbalog("wtf"); // TODO: REMOVE
}
}
u8 waitForMeaningfulByte() {
u32 lines = 0;
u32 vCount = Link::_REG_VCOUNT;
void receiveAsyncCommandSIO8(u32 newData) { // (irq only)
u8* commandBytes = (u8*)&asyncCommand.cmd;
u32 mainSize = PREAMBLE_SIZE + asyncCommand.cmd.packetHeader.dataSizeL;
u8 value = GBA_WAITING;
while ((value = transfer(GBA_WAITING)) == ADAPTER_WAITING) {
if (cmdTimeout(lines, vCount))
break;
if (asyncCommand.transferred == 0) {
// Magic Bytes (1)
if (newData == ADAPTER_WAITING)
return transferAsync(GBA_WAITING);
if (newData != COMMAND_MAGIC_VALUE1)
return asyncCommand.fail(CommandResult::INVALID_MAGIC_BYTES);
transferAsync(GBA_WAITING);
asyncCommand.transferred++;
} else if (asyncCommand.transferred == 1) {
// Magic Bytes (1)
if (newData != COMMAND_MAGIC_VALUE2)
return asyncCommand.fail(CommandResult::INVALID_MAGIC_BYTES);
transferAsync(GBA_WAITING);
asyncCommand.transferred++;
} else if (asyncCommand.transferred < PREAMBLE_SIZE) {
// Packet Header
commandBytes[asyncCommand.transferred] = newData;
if (asyncCommand.cmd.packetHeader._unusedDataSizeH_ != 0)
return asyncCommand.fail(CommandResult::WEIRD_DATA_SIZE);
transferAsync(GBA_WAITING);
asyncCommand.transferred++;
if (asyncCommand.transferred == PREAMBLE_SIZE)
asyncCommand.expectedChecksum = asyncCommand.cmd.packetHeader.sum();
} else if (asyncCommand.transferred < mainSize) {
// Packet Data
commandBytes[asyncCommand.transferred] = newData;
asyncCommand.expectedChecksum += newData;
transferAsync(GBA_WAITING);
asyncCommand.transferred++;
} else if (asyncCommand.transferred == mainSize) {
// Packet Checksum (1)
if (newData != msB16(asyncCommand.expectedChecksum))
return asyncCommand.fail(CommandResult::WRONG_CHECKSUM);
transferAsync(GBA_WAITING);
asyncCommand.transferred++;
} else if (asyncCommand.transferred == mainSize + 1) {
// Packet Checksum (2)
if (newData != lsB16(asyncCommand.expectedChecksum))
return asyncCommand.fail(CommandResult::WRONG_CHECKSUM);
transferAsync(DEVICE_GBA | OR_VALUE);
asyncCommand.transferred++;
} else if (asyncCommand.transferred == mainSize + CHECKSUM_SIZE) {
// Acknowledgement Signal (1)
if (!isSupportedAdapter(newData))
return asyncCommand.fail(CommandResult::INVALID_DEVICE_ID);
transferAsync(asyncCommand.cmd.packetHeader.commandId ^ OR_VALUE);
asyncCommand.transferred++;
} else if (asyncCommand.transferred == mainSize + CHECKSUM_SIZE + 1) {
// Acknowledgement Signal (2)
if (newData != 0)
return asyncCommand.fail(CommandResult::INVALID_COMMAND_ACK);
asyncCommand.result = CommandResult::SUCCESS;
asyncCommand.state = AsyncCommand::State::COMPLETED;
}
return value;
}
// TODO: USE?
// u8 waitForMeaningfulByte() {
// u32 lines = 0;
// u32 vCount = Link::_REG_VCOUNT;
// u8 value = GBA_WAITING;
// while ((value = transfer(GBA_WAITING)) == ADAPTER_WAITING) {
// if (cmdTimeout(lines, vCount))
// break;
// }
// return value;
// }
CommandResult acknowledge(u8 localCommandAck, u8 remoteCommandAck) {
if (!isSupportedAdapter(transfer(DEVICE_GBA | OR_VALUE)))
return CommandResult::INVALID_DEVICE_ID;