mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-04-26 02:02:25 -05:00
Adding basic commands to DebugScene
This commit is contained in:
parent
c0a79fd1a6
commit
88f6763863
|
|
@ -465,7 +465,7 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
|
|||
|
||||
* Returns some information about the current connection and device state. The returned word contains:
|
||||
- Bits `0-15`: The device ID (or zero if the device is not connected nor hosting).
|
||||
- Bits `16-23`: A 4-bit array indicating which slots are being used.
|
||||
- Bits `16-23`: A 4-bit array with slots. If the console is a client, it'll have a 1 in the position assigned to that slot (e.g. the one with `clientNumber` 3 will have `0100`). The host will always have `0000` here.
|
||||
- Bits `24-31`: A number indicating the state of the adapter
|
||||
- `0` = idle
|
||||
- `1`/`2` = serving (host)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
#include <tonc.h>
|
||||
#include <functional>
|
||||
|
||||
#include "../../../../lib/LinkRawWireless.hpp"
|
||||
#include "utils/InputHandler.h"
|
||||
|
|
@ -197,10 +198,11 @@ void DebugScene::processKeys(u16 keys) {
|
|||
|
||||
void DebugScene::processButtons() {
|
||||
if (aHandler->hasBeenPressedNow()) {
|
||||
int selectedCommand = selectOption(commandMenuOptions);
|
||||
if (selectedCommand > -1) {
|
||||
selectOption(std::vector<std::string>{"uno", "dos", "tres"});
|
||||
}
|
||||
int selectedCommandIndex =
|
||||
selectOption("Which command?", commandMenuOptions);
|
||||
if (selectedCommandIndex > -1)
|
||||
processCommand((u32)selectedCommandIndex);
|
||||
print();
|
||||
}
|
||||
|
||||
if (bHandler->hasBeenPressedNow())
|
||||
|
|
@ -244,7 +246,8 @@ void DebugScene::toggleLogLevel() {
|
|||
log("");
|
||||
}
|
||||
|
||||
int DebugScene::selectOption(std::vector<std::string> options) {
|
||||
int DebugScene::selectOption(std::string title,
|
||||
std::vector<std::string> options) {
|
||||
u32 selectedOption = 0;
|
||||
bool firstTime = true;
|
||||
|
||||
|
|
@ -272,7 +275,7 @@ int DebugScene::selectOption(std::vector<std::string> options) {
|
|||
selectedOption--;
|
||||
|
||||
if (firstTime || selectedOption != oldOption) {
|
||||
TextStream::instance().setText("Which command?", 0, -3);
|
||||
TextStream::instance().setText(title, 0, -3);
|
||||
printScrollableText(selectedOption, options, true);
|
||||
}
|
||||
|
||||
|
|
@ -287,9 +290,40 @@ int DebugScene::selectOption(std::vector<std::string> options) {
|
|||
}
|
||||
}
|
||||
|
||||
void DebugScene::resetAdapter() {
|
||||
log("> resetting adapter...");
|
||||
bool success = linkRawWireless->activate();
|
||||
log(success ? "< it worked :)" : "< it failed :(");
|
||||
void DebugScene::processCommand(u32 selectedCommandIndex) {
|
||||
std::string selectedCommand = commandMenuOptions[selectedCommandIndex];
|
||||
|
||||
if (selectedCommand == "0x10 (Hello)") {
|
||||
logSimpleCommand(selectedCommand, 0x11);
|
||||
} else if (selectedCommand == "0x11 (SignalLevel)") {
|
||||
logSimpleCommand(selectedCommand, 0x11);
|
||||
} else if (selectedCommand == "0x12 (VersionStatus)") {
|
||||
logSimpleCommand(selectedCommand, 0x12);
|
||||
} else if (selectedCommand == "0x13 (SystemStatus)") {
|
||||
logSimpleCommand(selectedCommand, 0x13);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugScene::logSimpleCommand(std::string name, u32 id) {
|
||||
logOperation("sending " + name, [id]() {
|
||||
auto result = linkRawWireless->sendCommand(id);
|
||||
for (u32 i = 0; i < result.responses.size(); i++) {
|
||||
log("< [response" + std::to_string(i) + "] " +
|
||||
linkRawWireless->toHex(result.responses[i]));
|
||||
}
|
||||
return result.success;
|
||||
});
|
||||
}
|
||||
|
||||
void DebugScene::logOperation(std::string name,
|
||||
std::function<bool()> operation) {
|
||||
log("> " + name + "...");
|
||||
bool success = operation();
|
||||
log(success ? "< success :)" : "< failure :(");
|
||||
log("");
|
||||
}
|
||||
}
|
||||
|
||||
void DebugScene::resetAdapter() {
|
||||
logOperation("resetting adapter",
|
||||
[]() { return linkRawWireless->activate(); });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@ class DebugScene : public Scene {
|
|||
void processKeys(u16 keys);
|
||||
void processButtons();
|
||||
void toggleLogLevel();
|
||||
int selectOption(std::vector<std::string> options);
|
||||
int selectOption(std::string title, std::vector<std::string> options);
|
||||
void processCommand(u32 selectedCommandIndex);
|
||||
void logSimpleCommand(std::string name, u32 id);
|
||||
void logOperation(std::string name, std::function<bool()> operation);
|
||||
void resetAdapter();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,11 @@ class LinkRawWireless {
|
|||
CONNECTED
|
||||
};
|
||||
|
||||
struct CommandResult {
|
||||
bool success = false;
|
||||
std::vector<u32> responses = std::vector<u32>{};
|
||||
};
|
||||
|
||||
enum Error {
|
||||
// TODO: REPLACE lastError with logger calls
|
||||
|
||||
|
|
@ -312,52 +317,6 @@ class LinkRawWireless {
|
|||
return true;
|
||||
}
|
||||
|
||||
u32 getDeviceTransferLength() {
|
||||
return state == SERVING ? LINK_RAW_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH
|
||||
: LINK_RAW_WIRELESS_MAX_CLIENT_TRANSFER_LENGTH;
|
||||
}
|
||||
|
||||
State getState() { return state; }
|
||||
bool isConnected() { return sessionState.playerCount > 1; }
|
||||
bool isSessionActive() { return state == SERVING || state == CONNECTED; }
|
||||
u8 playerCount() { return sessionState.playerCount; }
|
||||
u8 currentPlayerId() { return sessionState.currentPlayerId; }
|
||||
Error getLastError(bool clear = true) {
|
||||
Error error = lastError;
|
||||
if (clear)
|
||||
lastError = NONE;
|
||||
return error;
|
||||
}
|
||||
|
||||
~LinkRawWireless() {
|
||||
delete linkSPI;
|
||||
delete linkGPIO;
|
||||
}
|
||||
|
||||
private:
|
||||
struct SessionState {
|
||||
u8 playerCount = 1;
|
||||
u8 currentPlayerId = 0;
|
||||
u8 maxPlayers = LINK_RAW_WIRELESS_MAX_PLAYERS;
|
||||
};
|
||||
|
||||
struct LoginMemory {
|
||||
u16 previousGBAData = 0xffff;
|
||||
u16 previousAdapterData = 0xffff;
|
||||
};
|
||||
|
||||
struct CommandResult {
|
||||
bool success = false;
|
||||
std::vector<u32> responses = std::vector<u32>{};
|
||||
};
|
||||
|
||||
SessionState sessionState;
|
||||
LinkSPI* linkSPI = new LinkSPI();
|
||||
LinkGPIO* linkGPIO = new LinkGPIO();
|
||||
State state = NEEDS_RESET;
|
||||
Error lastError = NONE;
|
||||
volatile bool isEnabled = false;
|
||||
|
||||
bool sendData(std::vector<u32> data) {
|
||||
if ((state != SERVING && state != CONNECTED) || data.size() == 0 ||
|
||||
data.size() > LINK_RAW_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH)
|
||||
|
|
@ -397,6 +356,124 @@ class LinkRawWireless {
|
|||
return true;
|
||||
}
|
||||
|
||||
CommandResult sendCommand(u8 type,
|
||||
std::vector<u32> params = std::vector<u32>{}) {
|
||||
CommandResult result;
|
||||
u16 length = params.size();
|
||||
u32 command = buildCommand(type, length);
|
||||
u32 r;
|
||||
|
||||
logger("sending command 0x" + toHex(command));
|
||||
if ((r = transfer(command)) != LINK_RAW_WIRELESS_DATA_REQUEST) {
|
||||
logExpectedButReceived(LINK_RAW_WIRELESS_DATA_REQUEST, r);
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 parameterCount = 0;
|
||||
for (auto& param : params) {
|
||||
logger("sending param" + std::to_string(parameterCount) + ": 0x" +
|
||||
toHex(param));
|
||||
if ((r = transfer(param)) != LINK_RAW_WIRELESS_DATA_REQUEST) {
|
||||
logExpectedButReceived(LINK_RAW_WIRELESS_DATA_REQUEST, r);
|
||||
return result;
|
||||
}
|
||||
parameterCount++;
|
||||
}
|
||||
|
||||
logger("sending response request");
|
||||
u32 response = transfer(LINK_RAW_WIRELESS_DATA_REQUEST);
|
||||
u16 header = msB32(response);
|
||||
u16 data = lsB32(response);
|
||||
u8 responses = msB16(data);
|
||||
u8 ack = lsB16(data);
|
||||
|
||||
if (header != LINK_RAW_WIRELESS_COMMAND_HEADER) {
|
||||
logger("! expected HEADER 0x" + toHex(header));
|
||||
logger("! but received 0x" + toHex(header));
|
||||
return result;
|
||||
}
|
||||
if (ack != type + LINK_RAW_WIRELESS_RESPONSE_ACK) {
|
||||
if (ack == 0xee && responses == 1) {
|
||||
u8 code = (u8)transfer(LINK_RAW_WIRELESS_DATA_REQUEST);
|
||||
logger("! error received");
|
||||
logger(code == 1 ? "! invalid state" : "! unknown cmd");
|
||||
} else {
|
||||
logger("! expected ACK 0x" + toHex(header));
|
||||
logger("! but received 0x" + toHex(header));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
logger("ack ok! " + std::to_string(responses) + " responses");
|
||||
|
||||
for (u32 i = 0; i < responses; i++) {
|
||||
logger("response " + std::to_string(i + 1) + "/" +
|
||||
std::to_string(responses) + ":");
|
||||
u32 responseData = transfer(LINK_RAW_WIRELESS_DATA_REQUEST);
|
||||
result.responses.push_back(responseData);
|
||||
logger("<< " + std::to_string(responseData));
|
||||
}
|
||||
|
||||
result.success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 getDeviceTransferLength() {
|
||||
return state == SERVING ? LINK_RAW_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH
|
||||
: LINK_RAW_WIRELESS_MAX_CLIENT_TRANSFER_LENGTH;
|
||||
}
|
||||
|
||||
State getState() { return state; }
|
||||
bool isConnected() { return sessionState.playerCount > 1; }
|
||||
bool isSessionActive() { return state == SERVING || state == CONNECTED; }
|
||||
u8 playerCount() { return sessionState.playerCount; }
|
||||
u8 currentPlayerId() { return sessionState.currentPlayerId; }
|
||||
Error getLastError(bool clear = true) {
|
||||
Error error = lastError;
|
||||
if (clear)
|
||||
lastError = NONE;
|
||||
return error;
|
||||
}
|
||||
|
||||
~LinkRawWireless() {
|
||||
delete linkSPI;
|
||||
delete linkGPIO;
|
||||
}
|
||||
|
||||
template <typename I>
|
||||
std::string toHex(I w, size_t hex_len = sizeof(I) << 1) {
|
||||
static const char* digits = "0123456789ABCDEF";
|
||||
std::string rc(hex_len, '0');
|
||||
for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
|
||||
rc[i] = digits[(w >> j) & 0x0f];
|
||||
return rc;
|
||||
}
|
||||
|
||||
u32 buildU32(u16 msB, u16 lsB) { return (msB << 16) | lsB; }
|
||||
u16 buildU16(u8 msB, u8 lsB) { return (msB << 8) | lsB; }
|
||||
u16 msB32(u32 value) { return value >> 16; }
|
||||
u16 lsB32(u32 value) { return value & 0xffff; }
|
||||
u8 msB16(u16 value) { return value >> 8; }
|
||||
u8 lsB16(u16 value) { return value & 0xff; }
|
||||
|
||||
private:
|
||||
struct SessionState {
|
||||
u8 playerCount = 1;
|
||||
u8 currentPlayerId = 0;
|
||||
u8 maxPlayers = LINK_RAW_WIRELESS_MAX_PLAYERS;
|
||||
};
|
||||
|
||||
struct LoginMemory {
|
||||
u16 previousGBAData = 0xffff;
|
||||
u16 previousAdapterData = 0xffff;
|
||||
};
|
||||
|
||||
SessionState sessionState;
|
||||
LinkSPI* linkSPI = new LinkSPI();
|
||||
LinkGPIO* linkGPIO = new LinkGPIO();
|
||||
State state = NEEDS_RESET;
|
||||
Error lastError = NONE;
|
||||
volatile bool isEnabled = false;
|
||||
|
||||
void recoverName(std::string& name,
|
||||
u32 word,
|
||||
bool includeFirstTwoBytes = true) {
|
||||
|
|
@ -501,67 +578,6 @@ class LinkRawWireless {
|
|||
return true;
|
||||
}
|
||||
|
||||
CommandResult sendCommand(u8 type,
|
||||
std::vector<u32> params = std::vector<u32>{}) {
|
||||
CommandResult result;
|
||||
u16 length = params.size();
|
||||
u32 command = buildCommand(type, length);
|
||||
u32 r;
|
||||
|
||||
logger("sending command 0x" + toHex(command));
|
||||
if ((r = transfer(command)) != LINK_RAW_WIRELESS_DATA_REQUEST) {
|
||||
logExpectedButReceived(LINK_RAW_WIRELESS_DATA_REQUEST, r);
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 parameterCount = 0;
|
||||
for (auto& param : params) {
|
||||
logger("sending param" + std::to_string(parameterCount) + ": 0x" +
|
||||
toHex(param));
|
||||
if ((r = transfer(param)) != LINK_RAW_WIRELESS_DATA_REQUEST) {
|
||||
logExpectedButReceived(LINK_RAW_WIRELESS_DATA_REQUEST, r);
|
||||
return result;
|
||||
}
|
||||
parameterCount++;
|
||||
}
|
||||
|
||||
logger("sending response request");
|
||||
u32 response = transfer(LINK_RAW_WIRELESS_DATA_REQUEST);
|
||||
u16 header = msB32(response);
|
||||
u16 data = lsB32(response);
|
||||
u8 responses = msB16(data);
|
||||
u8 ack = lsB16(data);
|
||||
|
||||
if (header != LINK_RAW_WIRELESS_COMMAND_HEADER) {
|
||||
logger("! expected HEADER 0x" + toHex(header));
|
||||
logger("! but received 0x" + toHex(header));
|
||||
return result;
|
||||
}
|
||||
if (ack != type + LINK_RAW_WIRELESS_RESPONSE_ACK) {
|
||||
if (ack == 0xee && responses == 1) {
|
||||
u8 code = (u8)transfer(LINK_RAW_WIRELESS_DATA_REQUEST);
|
||||
logger("! error received");
|
||||
logger(code == 1 ? "! invalid state" : "! unknown cmd");
|
||||
} else {
|
||||
logger("! expected ACK 0x" + toHex(header));
|
||||
logger("! but received 0x" + toHex(header));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
logger("ack ok! " + std::to_string(responses) + " responses");
|
||||
|
||||
for (u32 i = 0; i < responses; i++) {
|
||||
logger("response " + std::to_string(i + 1) + "/" +
|
||||
std::to_string(responses) + ":");
|
||||
u32 responseData = transfer(LINK_RAW_WIRELESS_DATA_REQUEST);
|
||||
result.responses.push_back(responseData);
|
||||
logger("<< " + std::to_string(responseData));
|
||||
}
|
||||
|
||||
result.success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 buildCommand(u8 type, u8 length = 0) {
|
||||
return buildU32(LINK_RAW_WIRELESS_COMMAND_HEADER, buildU16(length, type));
|
||||
}
|
||||
|
|
@ -636,22 +652,6 @@ class LinkRawWireless {
|
|||
logger("! expected 0x" + toHex(expected));
|
||||
logger("! but received 0x" + toHex(received));
|
||||
}
|
||||
|
||||
template <typename I>
|
||||
std::string toHex(I w, size_t hex_len = sizeof(I) << 1) {
|
||||
static const char* digits = "0123456789ABCDEF";
|
||||
std::string rc(hex_len, '0');
|
||||
for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
|
||||
rc[i] = digits[(w >> j) & 0x0f];
|
||||
return rc;
|
||||
}
|
||||
|
||||
u32 buildU32(u16 msB, u16 lsB) { return (msB << 16) | lsB; }
|
||||
u16 buildU16(u8 msB, u8 lsB) { return (msB << 8) | lsB; }
|
||||
u16 msB32(u32 value) { return value >> 16; }
|
||||
u16 lsB32(u32 value) { return value & 0xffff; }
|
||||
u8 msB16(u16 value) { return value >> 8; }
|
||||
u8 lsB16(u16 value) { return value & 0xff; }
|
||||
};
|
||||
|
||||
extern LinkRawWireless* linkRawWireless;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user