From 7dd0c0d44ccf6e596fe138a15518c10f448b3993 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Mon, 15 Jan 2024 05:01:54 -0300 Subject: [PATCH] Refactoring and adding docs --- README.md | 64 +++++++++++++++++++++-------------- lib/LinkRawWireless.hpp | 75 ++++++++++++++--------------------------- 2 files changed, 63 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 93affad..947d266 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,12 @@ A set of Game Boy Advance (GBA) C++ libraries to interact with the Serial Port. Its main purpose is to provide multiplayer support to homebrew games. - [πŸ‘Ύ](#-LinkCable) [LinkCable.hpp](lib/LinkCable.hpp): The classic 16-bit **Multi-Play mode** (up to 4 players) using a GBA Link Cable! - - [πŸ”§πŸ‘Ύ](#-LinkRawCable) [LinkRawCable.hpp](lib/LinkRawCable.hpp): A **minimal** low-level API for the 16-bit multiplayer mode. + - [πŸ”§πŸ‘Ύ](#-LinkRawCable) [LinkRawCable.hpp](lib/LinkRawCable.hpp): A **minimal** low-level API for the 16-bit Multi-Play mode. - [πŸ’»](#-LinkCableMultiboot) [LinkCableMultiboot.hpp](lib/LinkCableMultiboot.hpp): ‍Send **Multiboot software** (small 256KiB ROMs) to other GBAs with no cartridge! - [πŸ”Œ](#-LinkGPIO) [LinkGPIO.hpp](lib/LinkGPIO.hpp): Use the Link Port however you want to control **any device** (like LEDs, rumble motors, and that kind of stuff)! - [πŸ”—](#-LinkSPI) [LinkSPI.hpp](lib/LinkSPI.hpp): Connect with a PC (like a **Raspberry Pi**) or another GBA (with a GBC Link Cable) using this mode. Transfer up to 2Mbit/s! - [πŸ“»](#-LinkWireless) [LinkWireless.hpp](lib/LinkWireless.hpp): Connect up to 5 consoles with the **Wireless Adapter**! + - [πŸ”§πŸ“»](#-LinkRawWireless) [LinkRawWireless.hpp](lib/LinkRawWireless.hpp): A **minimal** low-level API for the Wireless Adapter. - [🌎](#-LinkUniversal) [LinkUniversal.hpp](lib/LinkUniversal.hpp): Add multiplayer support to your game, both with πŸ‘Ύ *Link Cables* and πŸ“» *Wireless Adapters*, using the **same API**. *(click on the emojis for documentation)* @@ -78,31 +79,6 @@ Name | Return type | Description ⚠️ `0xFFFF` and `0x0` are reserved values, so don't send them! -# πŸ”§πŸ‘Ύ LinkRawCable - -- This is a minimal hardware wrapper designed for the *multiplayer mode*. -- It doesn't include any of the features of [πŸ‘Ύ LinkCable](#-LinkCable), so it's not well suited for games. -- Its demo (`LinkRawCable_demo`) can help emulator developers in enhancing accuracy. - -## Methods - -Name | Return type | Description ---- | --- | --- -`isActive()` | **bool** | Returns whether the library is active or not. -`activate(baudRate = BAUD_RATE_1)` | - | Activates the library in a specific `baudRate` (`LinkRawCable::BaudRate`). -`deactivate()` | - | Deactivates the library. -`transfer(data)` | **LinkRawCable::Response** | Exchanges `data` with the other end. Returns the received data, including the assigned player id. -`transfer(data, cancel)` | **LinkRawCable::Response** | Like `transfer(data)` but accepts a `cancel()` function. The library will continuously invoke it, and abort the transfer if it returns `true`. -`transferAsync(data)` | - | Schedules a `data` transfer and returns. After this, call `getAsyncState()` and `getAsyncData()`. Note that until you retrieve the async data, normal `transfer(...)`s won't do anything! -`getAsyncState()` | **LinkRawCable::AsyncState** | Returns the state of the last async transfer (one of `LinkRawCable::AsyncState::IDLE`, `LinkRawCable::AsyncState::WAITING`, or `LinkRawCable::AsyncState::READY`). -`getAsyncData()` | **LinkRawCable::Response** | If the async state is `READY`, returns the remote data and switches the state back to `IDLE`. -`isMaster()` | **bool** | Returns whether the console is connected as master or not. Returns garbage when the cable is not properly connected. -`isReady()` | **bool** | Returns whether all connected consoles have entered the multiplayer mode. Returns garbage when the cable is not properly connected. -`getBaudRate()` | **LinkRawCable::BaudRate** | Returns the current `baudRate`. - -- don't send `0xFFFF`, it's a reserved value that means *disconnected client* -- only `transfer(...)` if `isReady()` - # πŸ’» LinkCableMultiboot *(aka Multiboot through Multi-Play mode)* @@ -267,3 +243,39 @@ Name | Return type | Description `getProtocol()` | **LinkUniversal::Protocol** | Returns the active protocol (one of `LinkUniversal::Protocol::AUTODETECT`, `LinkUniversal::Protocol::CABLE`, `LinkUniversal::Protocol::WIRELESS_AUTO`, `LinkUniversal::Protocol::WIRELESS_SERVER`, or `LinkUniversal::Protocol::WIRELESS_CLIENT`). `setProtocol(protocol)` | - | Sets the active `protocol`. `getWirelessState()` | **LinkWireless::State** | Returns the wireless state (same as [πŸ“» LinkWireless](#methods-4)'s `getState()`). + +# πŸ”§πŸ‘Ύ LinkRawCable + +- This is a minimal hardware wrapper designed for the *Multi-Play mode*. +- It doesn't include any of the features of [πŸ‘Ύ LinkCable](#-LinkCable), so it's not well suited for games. +- Its demo (`LinkRawCable_demo`) can help emulator developers in enhancing accuracy. + +## Methods + +Name | Return type | Description +--- | --- | --- +`isActive()` | **bool** | Returns whether the library is active or not. +`activate(baudRate = BAUD_RATE_1)` | - | Activates the library in a specific `baudRate` (`LinkRawCable::BaudRate`). +`deactivate()` | - | Deactivates the library. +`transfer(data)` | **LinkRawCable::Response** | Exchanges `data` with the other end. Returns the received data, including the assigned player id. +`transfer(data, cancel)` | **LinkRawCable::Response** | Like `transfer(data)` but accepts a `cancel()` function. The library will continuously invoke it, and abort the transfer if it returns `true`. +`transferAsync(data)` | - | Schedules a `data` transfer and returns. After this, call `getAsyncState()` and `getAsyncData()`. Note that until you retrieve the async data, normal `transfer(...)`s won't do anything! +`getAsyncState()` | **LinkRawCable::AsyncState** | Returns the state of the last async transfer (one of `LinkRawCable::AsyncState::IDLE`, `LinkRawCable::AsyncState::WAITING`, or `LinkRawCable::AsyncState::READY`). +`getAsyncData()` | **LinkRawCable::Response** | If the async state is `READY`, returns the remote data and switches the state back to `IDLE`. +`isMaster()` | **bool** | Returns whether the console is connected as master or not. Returns garbage when the cable is not properly connected. +`isReady()` | **bool** | Returns whether all connected consoles have entered the multiplayer mode. Returns garbage when the cable is not properly connected. +`getBaudRate()` | **LinkRawCable::BaudRate** | Returns the current `baudRate`. + +- don't send `0xFFFF`, it's a reserved value that means *disconnected client* +- only `transfer(...)` if `isReady()` + +# πŸ”§πŸ“» LinkRawWireless + +- This is a minimal hardware wrapper designed for the *Wireless Adapter*. +- It doesn't include any of the features of [πŸ“» LinkWireless](#-LinkWireless), so it's not well suited for games. +- Its demo (`LinkRawWireless_demo`) can help emulator developers in enhancing accuracy. + +## Methods + +- There's one method for every supported wireless adapter command. +- Use `sendCommand(...)` to send arbitrary commands. \ No newline at end of file diff --git a/lib/LinkRawWireless.hpp b/lib/LinkRawWireless.hpp index f431096..244a5c5 100644 --- a/lib/LinkRawWireless.hpp +++ b/lib/LinkRawWireless.hpp @@ -4,7 +4,7 @@ // -------------------------------------------------------------------------- // A low level driver for the GBA Wireless Adapter. // -------------------------------------------------------------------------- -// - Advanced usage only (check out the documentation). +// - Advanced usage only! // - If you're building a game, use `LinkWireless`. // -------------------------------------------------------------------------- @@ -16,8 +16,6 @@ #include #include -// TODO: LOGGING BUILD OPTION - #define LINK_RAW_WIRELESS_MAX_PLAYERS 5 #define LINK_RAW_WIRELESS_MIN_PLAYERS 2 #define LINK_RAW_WIRELESS_END 0 @@ -83,19 +81,6 @@ class LinkRawWireless { std::vector responses = std::vector{}; }; - enum Error { - // TODO: REPLACE lastError with logger calls - - // User errors - NONE = 0, - GAME_NAME_TOO_LONG = 1, - USER_NAME_TOO_LONG = 2, - // Communication errors - COMMAND_FAILED = 5, - CONNECTION_FAILED = 6, - ACKNOWLEDGE_FAILED = 9, - }; - struct Server { u16 id = 0; u16 gameId; @@ -106,10 +91,30 @@ class LinkRawWireless { bool isFull() { return nextClientNumber == 0xff; } }; + typedef struct { + u16 deviceId = 0; + u8 clientNumber = 0; + } ConnectedClient; + + typedef struct { + u8 nextClientNumber = 0; + std::vector connectedClients = {}; + } SlotStatusResponse; + + typedef struct { + std::vector connectedClients = {}; + } AcceptConnectionsResponse; + + enum ConnectionPhase { STILL_CONNECTING, ERROR, SUCCESS }; + + typedef struct { + ConnectionPhase phase = STILL_CONNECTING; + u8 assignedClientNumber = 0; + } ConnectionStatus; + bool isActive() { return isEnabled; } bool activate() { - lastError = NONE; isEnabled = false; bool success = reset(true); @@ -121,7 +126,6 @@ class LinkRawWireless { bool deactivate() { bool success = sendCommand(LINK_RAW_WIRELESS_COMMAND_BYE).success; - lastError = NONE; isEnabled = false; resetState(); stop(); @@ -143,11 +147,11 @@ class LinkRawWireless { std::string userName = "", u16 gameId = LINK_RAW_WIRELESS_MAX_GAME_ID) { if (gameName.length() > LINK_RAW_WIRELESS_MAX_GAME_NAME_LENGTH) { - lastError = GAME_NAME_TOO_LONG; + logger("! game name too long"); return false; } if (userName.length() > LINK_RAW_WIRELESS_MAX_GAME_NAME_LENGTH) { - lastError = USER_NAME_TOO_LONG; + logger("! user name too long"); return false; } gameName.append(LINK_RAW_WIRELESS_MAX_GAME_NAME_LENGTH - gameName.length(), @@ -185,7 +189,6 @@ class LinkRawWireless { if (!success) { reset(); - lastError = COMMAND_FAILED; return false; } @@ -196,14 +199,6 @@ class LinkRawWireless { return true; } - typedef struct { - u16 deviceId = 0; - u8 clientNumber = 0; - } ConnectedClient; - typedef struct { - u8 nextClientNumber = 0; - std::vector connectedClients = {}; - } SlotStatusResponse; bool getSlotStatus(SlotStatusResponse& response) { auto result = sendCommand(LINK_RAW_WIRELESS_COMMAND_SLOT_STATUS); @@ -225,9 +220,6 @@ class LinkRawWireless { return true; } - typedef struct { - std::vector connectedClients = {}; - } AcceptConnectionsResponse; bool acceptConnections(AcceptConnectionsResponse& response) { auto result = sendCommand(LINK_RAW_WIRELESS_COMMAND_ACCEPT_CONNECTIONS); @@ -249,6 +241,7 @@ class LinkRawWireless { return true; } + bool endHost(AcceptConnectionsResponse& response) { auto result = sendCommand(LINK_RAW_WIRELESS_COMMAND_END_HOST); @@ -277,7 +270,6 @@ class LinkRawWireless { if (!success) { reset(); - lastError = COMMAND_FAILED; return false; } @@ -296,7 +288,6 @@ class LinkRawWireless { if (!success) { reset(); - lastError = COMMAND_FAILED; return false; } @@ -346,7 +337,6 @@ class LinkRawWireless { if (!success) { reset(); - lastError = COMMAND_FAILED; return false; } @@ -356,11 +346,6 @@ class LinkRawWireless { return true; } - enum ConnectionPhase { STILL_CONNECTING, ERROR, SUCCESS }; - typedef struct { - ConnectionPhase phase = STILL_CONNECTING; - u8 assignedClientNumber = 0; - } ConnectionStatus; bool keepConnecting(ConnectionStatus& response) { auto result = sendCommand(LINK_RAW_WIRELESS_COMMAND_IS_FINISHED_CONNECT); if (!result.success || result.responses.size() == 0) { @@ -429,7 +414,6 @@ class LinkRawWireless { if (!success) { reset(); - // TODO: ERRORS? return false; } @@ -442,7 +426,6 @@ class LinkRawWireless { if (!result.success) { reset(); - // TODO: ERRORS? return false; } @@ -523,12 +506,6 @@ class LinkRawWireless { 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; @@ -538,7 +515,6 @@ class LinkRawWireless { struct SessionState { u8 playerCount = 1; u8 currentPlayerId = 0; - u8 maxPlayers = LINK_RAW_WIRELESS_MAX_PLAYERS; }; struct LoginMemory { @@ -550,7 +526,6 @@ class LinkRawWireless { LinkSPI* linkSPI = new LinkSPI(); LinkGPIO* linkGPIO = new LinkGPIO(); State state = NEEDS_RESET; - Error lastError = NONE; volatile bool isEnabled = false; void recoverName(std::string& name,