diff --git a/README.md b/README.md index a09960f..8135b64 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ Name | Return type | Description `isActive()` | **bool** | Returns whether the library is active or not. `activate()` | **bool** | Activates the library. When an adapter is connected, it changes the state to `AUTHENTICATED`. It can also be used to disconnect or reset the adapter. `deactivate()` | **bool** | Puts the adapter into a low consumption mode and then deactivates the library. It returns a boolean indicating whether the transition to low consumption mode was successful. -`serve([gameName], [userName], [gameId], [isUpdate])` | **bool** | Starts broadcasting a server and changes the state to `SERVING`. You can, optionally, provide a `gameName` (max `14` characters), a `userName` (max `8` characters), and a `gameId` *(0 ~ 0x7FFF)* that games will be able to read. If `isUpdate` is true, this method only updates the broadcast data. +`serve([gameName], [userName], [gameId])` | **bool** | Starts broadcasting a server and changes the state to `SERVING`. You can, optionally, provide a `gameName` (max `14` characters), a `userName` (max `8` characters), and a `gameId` *(0 ~ 0x7FFF)* that games will be able to read. If the adapter is already serving, this method only updates the broadcast data. `getServers(servers, [onWait])` | **bool** | Fills the `servers` array with all the currently broadcasting servers. This action takes 1 second to complete, but you can optionally provide an `onWait()` function which will be invoked each time VBlank starts. `getServersAsyncStart()` | **bool** | Starts looking for broadcasting servers and changes the state to `SEARCHING`. After this, call `getServersAsyncEnd(...)` 1 second later. `getServersAsyncEnd(servers)` | **bool** | Fills the `servers` array with all the currently broadcasting servers. Changes the state to `AUTHENTICATED` again. diff --git a/docs/wireless_adapter.md b/docs/wireless_adapter.md index 28f4035..c9d2f69 100644 --- a/docs/wireless_adapter.md +++ b/docs/wireless_adapter.md @@ -233,6 +233,14 @@ Whenever either side expects something to be sent from the other (as SPI is alwa Both Pokemon games and the multiboot ROM that the adapter sends when no cartridge is inserted use `0x003C0420`. +🔝 For a game, the most important bits are bits `16-17` (let's call this `maxPlayers`), which specify the maximum number of allowed players: +- `00`: 5 players (1 host and 4 clients) +- `01`: 4 players +- `10`: 3 players +- `11`: 2 players + +⚠️ Clients must always set `maxPlayers` to `00`. + #### Broadcast - `0x16` [![Image without alt text or caption](img/0x16.png)](img/0x16.png) @@ -265,14 +273,22 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg - Clients cannot connect, even if they already know the host ID (`FinishConnection` will fail). - Calls to `AcceptConnections` on the host side will fail. -#### BroadcastRead - `0x1d`, `0x1e` and `0x1c` +#### BroadcastRead - `0x1c`, `0x1d` and `0x1e` [![Image without alt text or caption](img/0x1d.png)](img/0x1d.png) -* Send length: 0, response length: 7 \* number of broadcasts +* Send length: 0, response length: 7 \* number of broadcasts (maximum: 4) -* All currently broadcasting devices are returned here along with an ID at the start of each. -* IDs have 16 bits. +* All currently broadcasting devices are returned here along with a word of **metadata** (the metadata word first, then 6 words with broadcast data). +* The metadata contains: + * First 2 bytes: Server ID. IDs have 16 bits. + * 3rd byte: Available slots. This can be used to check whether a player can join a room or not. + * `0b00`: No one is connected yet (just the host). + * `0b01`: There is 1 connected client, and there's room for more. + * `0b10`: There are 2 connected clients, and there's room for more. + * `0b11`: There are 3 connected clients, and there's room for more. + * `0xff`: The server is full. The number of connected players is unknown, as it depends on `maxPlayers` (see [Setup](#setup---0x17)). + * 4th byte: Zero. 🆔 IDs are randomly generated. Each time you broadcast or connect, the adapter assigns you a new id. @@ -297,7 +313,7 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg * Send length: 1, response length: 0 -* Send the ID of the adapter you want to connect to from [BroadcastRead](#broadcastread---0x1d-0x1e-and-0x1c). +* Send the ID of the adapter you want to connect to from [BroadcastRead](#broadcastread---0x1c-0x1d-and-0x1e). #### IsFinishedConnect - `0x20` diff --git a/examples/LinkUniversal_basic/src/main.cpp b/examples/LinkUniversal_basic/src/main.cpp index 474b3f6..4c48408 100644 --- a/examples/LinkUniversal_basic/src/main.cpp +++ b/examples/LinkUniversal_basic/src/main.cpp @@ -21,10 +21,10 @@ void init() { int main() { init(); - log("Press A to start\n\n\n\n\n\n\n\n\nhold LEFT on start:\n -> force " + log("Press A to start\n\n\n\n\nhold LEFT on start:\n -> force " "cable\n\nhold RIGHT on start:\n -> force wireless\n\nhold UP on " "start:\n -> force wireless server\n\nhold DOWN on start:\n -> force " - "wireless client"); + "wireless client\n\nhold B on start:\n -> set 2 players (wireless)"); waitFor(KEY_A); u16 initialKeys = ~REG_KEYS & KEY_ANY; bool forceCable = initialKeys & KEY_LEFT; @@ -37,9 +37,25 @@ int main() { : forceWirelessServer ? LinkUniversal::Protocol::WIRELESS_SERVER : forceWirelessClient ? LinkUniversal::Protocol::WIRELESS_CLIENT : LinkUniversal::Protocol::AUTODETECT; + u32 maxPlayers = (initialKeys & KEY_B) ? 2 : LINK_UNIVERSAL_MAX_PLAYERS; // (1) Create a LinkUniversal instance - linkUniversal = new LinkUniversal(protocol); + linkUniversal = new LinkUniversal( + protocol, "LinkUNI", + (LinkUniversal::CableOptions){ + .baudRate = LinkCable::BAUD_RATE_1, + .timeout = LINK_CABLE_DEFAULT_TIMEOUT, + .remoteTimeout = LINK_CABLE_DEFAULT_REMOTE_TIMEOUT, + .interval = LINK_CABLE_DEFAULT_INTERVAL, + .sendTimerId = LINK_CABLE_DEFAULT_SEND_TIMER_ID}, + (LinkUniversal::WirelessOptions){ + .retransmission = true, + .maxPlayers = maxPlayers, + .timeout = LINK_WIRELESS_DEFAULT_TIMEOUT, + .remoteTimeout = LINK_WIRELESS_DEFAULT_REMOTE_TIMEOUT, + .interval = LINK_WIRELESS_DEFAULT_INTERVAL, + .sendTimerId = LINK_WIRELESS_DEFAULT_SEND_TIMER_ID, + .asyncACKTimerId = LINK_WIRELESS_DEFAULT_ASYNC_ACK_TIMER_ID}); // (2) Add the required interrupt service routines interrupt_init(); diff --git a/examples/LinkWireless_demo/src/main.cpp b/examples/LinkWireless_demo/src/main.cpp index 8a76419..73877e6 100644 --- a/examples/LinkWireless_demo/src/main.cpp +++ b/examples/LinkWireless_demo/src/main.cpp @@ -27,6 +27,7 @@ void connect(); void messageLoop(); void log(std::string text); void waitFor(u16 key); +void wait(u32 verticalLines); void hang(); LinkWireless::Error lastError; @@ -198,13 +199,18 @@ void connect() { return; } else { std::string str = "Press START to connect\n(first ID will be used)\n\n"; - for (u32 i = 0; i < LINK_WIRELESS_MAX_SERVERS; i++) { + for (u32 i = 0; i < 3; i++) { auto server = servers[i]; if (server.id == LINK_WIRELESS_END) break; - str += std::to_string(server.id) + " (" + std::to_string(server.gameId) + - ")\n"; + str += + std::to_string(server.id) + + (server.isFull() ? " [full]" + : " [" + std::to_string(server.currentPlayerCount) + + " online]") + + "\n"; + str += " -> gameID: " + std::to_string(server.gameId) + "\n"; if (server.gameName.length() > 0) str += " -> game: " + server.gameName + "\n"; if (server.userName.length() > 0) @@ -308,10 +314,10 @@ void messageLoop() { sending = false; // (7) Receive data - LinkWireless::Message messages[LINK_WIRELESS_MAX_TRANSFER_LENGTH]; + LinkWireless::Message messages[LINK_WIRELESS_QUEUE_SIZE]; linkWireless->receive(messages); if (messages[0].packetId != LINK_WIRELESS_END) { - for (u32 i = 0; i < LINK_WIRELESS_MAX_TRANSFER_LENGTH; i++) { + for (u32 i = 0; i < LINK_WIRELESS_QUEUE_SIZE; i++) { auto message = messages[i]; if (message.packetId == LINK_WIRELESS_END) break; @@ -419,7 +425,7 @@ void messageLoop() { #ifndef PROFILING_ENABLED if (lostPackets > 0) { output += "\n\n_lostPackets: " + std::to_string(lostPackets) + "\n"; - output += "_last: (" + std::to_string(lastLostPacketPlayerId) + "->" + + output += "_last: (" + std::to_string(lastLostPacketPlayerId) + ":" + std::to_string(lastLostPacketReceivedPacketId) + ") " + std::to_string(lastLostPacketReceived) + " [vs " + std::to_string(lastLostPacketExpected) + "]"; @@ -427,6 +433,10 @@ void messageLoop() { #endif } + // Test lag + if (keys & KEY_DOWN) + wait(9000); + // Print VBlankIntrWait(); log(output); @@ -446,6 +456,18 @@ void waitFor(u16 key) { } while (!(keys & key)); } +void wait(u32 verticalLines) { + u32 count = 0; + u32 vCount = REG_VCOUNT; + + while (count < verticalLines) { + if (REG_VCOUNT != vCount) { + count++; + vCount = REG_VCOUNT; + } + }; +} + void hang() { waitFor(KEY_DOWN); } \ No newline at end of file diff --git a/examples/compile.sh b/examples/compile.sh index 66ddf85..22faf96 100644 --- a/examples/compile.sh +++ b/examples/compile.sh @@ -31,8 +31,10 @@ cp LinkSPI_demo.gba ../ cd .. cd LinkUniversal_basic/ +sed -i -e "s/\/\/ #define LINK_WIRELESS_PUT_ISR_IN_IWRAM/#define LINK_WIRELESS_PUT_ISR_IN_IWRAM/g" ../../lib/LinkWireless.hpp make rebuild cp LinkUniversal_basic.gba ../ +sed -i -e "s/#define LINK_WIRELESS_PUT_ISR_IN_IWRAM/\/\/ #define LINK_WIRELESS_PUT_ISR_IN_IWRAM/g" ../../lib/LinkWireless.hpp cd .. cd LinkCable_full/ diff --git a/lib/LinkCable.hpp b/lib/LinkCable.hpp index 6d4383d..b208bd5 100644 --- a/lib/LinkCable.hpp +++ b/lib/LinkCable.hpp @@ -62,7 +62,7 @@ #define LINK_CABLE_BIT_GENERAL_PURPOSE_HIGH 15 #define LINK_CABLE_BARRIER asm volatile("" ::: "memory") -static volatile char LINK_CABLE_VERSION[] = "LinkCable/v6.0.2"; +static volatile char LINK_CABLE_VERSION[] = "LinkCable/v6.0.3"; void LINK_CABLE_ISR_VBLANK(); void LINK_CABLE_ISR_SERIAL(); diff --git a/lib/LinkCableMultiboot.hpp b/lib/LinkCableMultiboot.hpp index 66520f5..9e1addd 100644 --- a/lib/LinkCableMultiboot.hpp +++ b/lib/LinkCableMultiboot.hpp @@ -58,7 +58,7 @@ return error(FAILURE_DURING_HANDSHAKE); static volatile char LINK_CABLE_MULTIBOOT_VERSION[] = - "LinkCableMultiboot/v6.0.2"; + "LinkCableMultiboot/v6.0.3"; const u8 LINK_CABLE_MULTIBOOT_CLIENT_IDS[] = {0b0010, 0b0100, 0b1000}; diff --git a/lib/LinkGPIO.hpp b/lib/LinkGPIO.hpp index ed046be..3cda63a 100644 --- a/lib/LinkGPIO.hpp +++ b/lib/LinkGPIO.hpp @@ -35,7 +35,7 @@ else \ REG &= ~(1 << BIT); -static volatile char LINK_GPIO_VERSION[] = "LinkGPIO/v6.0.2"; +static volatile char LINK_GPIO_VERSION[] = "LinkGPIO/v6.0.3"; const u8 LINK_GPIO_DATA_BITS[] = {2, 3, 1, 0}; const u8 LINK_GPIO_DIRECTION_BITS[] = {6, 7, 5, 4}; diff --git a/lib/LinkSPI.hpp b/lib/LinkSPI.hpp index 9159268..176b668 100644 --- a/lib/LinkSPI.hpp +++ b/lib/LinkSPI.hpp @@ -49,7 +49,7 @@ #define LINK_SPI_BIT_GENERAL_PURPOSE_LOW 14 #define LINK_SPI_BIT_GENERAL_PURPOSE_HIGH 15 -static volatile char LINK_SPI_VERSION[] = "LinkSPI/v6.0.2"; +static volatile char LINK_SPI_VERSION[] = "LinkSPI/v6.0.3"; class LinkSPI { public: diff --git a/lib/LinkUniversal.hpp b/lib/LinkUniversal.hpp index 756e87f..c8322da 100644 --- a/lib/LinkUniversal.hpp +++ b/lib/LinkUniversal.hpp @@ -40,6 +40,7 @@ #include #include +#include #include "LinkCable.hpp" #include "LinkWireless.hpp" @@ -47,8 +48,6 @@ #define LINK_UNIVERSAL_DISCONNECTED LINK_CABLE_DISCONNECTED #define LINK_UNIVERSAL_NO_DATA LINK_CABLE_NO_DATA #define LINK_UNIVERSAL_MAX_ROOM_NUMBER 32000 -#define LINK_UNIVERSAL_FULL_ROOM_NUMBER 32001 -#define LINK_UNIVERSAL_FULL_ROOM_NUMBER_STR "32001" #define LINK_UNIVERSAL_INIT_WAIT_FRAMES 10 #define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES 25 #define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES_RANDOM 10 @@ -56,7 +55,7 @@ #define LINK_UNIVERSAL_SERVE_WAIT_FRAMES 60 #define LINK_UNIVERSAL_SERVE_WAIT_FRAMES_RANDOM 30 -static volatile char LINK_UNIVERSAL_VERSION[] = "LinkUniversal/v6.0.2"; +static volatile char LINK_UNIVERSAL_VERSION[] = "LinkUniversal/v6.0.3"; void LINK_UNIVERSAL_ISR_VBLANK(); void LINK_UNIVERSAL_ISR_SERIAL(); @@ -101,7 +100,7 @@ class LinkUniversal { LINK_CABLE_DEFAULT_REMOTE_TIMEOUT, LINK_CABLE_DEFAULT_INTERVAL, LINK_CABLE_DEFAULT_SEND_TIMER_ID}, WirelessOptions wirelessOptions = WirelessOptions{ - true, LINK_WIRELESS_MAX_PLAYERS, LINK_WIRELESS_DEFAULT_TIMEOUT, + true, LINK_UNIVERSAL_MAX_PLAYERS, LINK_WIRELESS_DEFAULT_TIMEOUT, LINK_WIRELESS_DEFAULT_REMOTE_TIMEOUT, LINK_WIRELESS_DEFAULT_INTERVAL, LINK_WIRELESS_DEFAULT_SEND_TIMER_ID, LINK_WIRELESS_DEFAULT_ASYNC_ACK_TIMER_ID}) { @@ -109,7 +108,8 @@ class LinkUniversal { cableOptions.baudRate, cableOptions.timeout, cableOptions.remoteTimeout, cableOptions.interval, cableOptions.sendTimerId); this->linkWireless = new LinkWireless( - wirelessOptions.retransmission, true, wirelessOptions.maxPlayers, + wirelessOptions.retransmission, true, + min(wirelessOptions.maxPlayers, LINK_UNIVERSAL_MAX_PLAYERS), wirelessOptions.timeout, wirelessOptions.remoteTimeout, wirelessOptions.interval, wirelessOptions.sendTimerId, wirelessOptions.asyncACKTimerId); @@ -210,15 +210,6 @@ class LinkUniversal { } receiveWirelessMessages(); - - if (!linkWireless->_hasActiveAsyncCommand() && - linkWireless->playerCount() == linkWireless->config.maxPlayers && - !didCloseWirelessRoom) { - linkWireless->serve(config.gameName, - LINK_UNIVERSAL_FULL_ROOM_NUMBER_STR, - LINK_WIRELESS_MAX_GAME_ID, true); - didCloseWirelessRoom = true; - } } break; @@ -316,7 +307,6 @@ class LinkUniversal { u32 switchWait = 0; u32 subWaitCount = 0; u32 serveWait = 0; - bool didCloseWirelessRoom = false; volatile bool isEnabled = false; void receiveCableMessages() { @@ -327,10 +317,10 @@ class LinkUniversal { } void receiveWirelessMessages() { - LinkWireless::Message messages[LINK_WIRELESS_MAX_TRANSFER_LENGTH]; + LinkWireless::Message messages[LINK_WIRELESS_QUEUE_SIZE]; linkWireless->receive(messages); - for (u32 i = 0; i < LINK_WIRELESS_MAX_TRANSFER_LENGTH; i++) { + for (u32 i = 0; i < LINK_WIRELESS_QUEUE_SIZE; i++) { auto message = messages[i]; if (message.packetId == LINK_WIRELESS_END) break; @@ -393,10 +383,10 @@ class LinkUniversal { if (server.id == LINK_WIRELESS_END) break; - if (server.gameName == config.gameName) { + if (!server.isFull() && server.gameName == config.gameName) { u32 randomNumber = safeStoi(server.userName); if (randomNumber > maxRandomNumber && - randomNumber < LINK_UNIVERSAL_FULL_ROOM_NUMBER) { + randomNumber < LINK_UNIVERSAL_MAX_ROOM_NUMBER) { maxRandomNumber = randomNumber; serverIndex = i; } @@ -491,7 +481,6 @@ class LinkUniversal { serveWait = 0; for (u32 i = 0; i < LINK_UNIVERSAL_MAX_PLAYERS; i++) incomingMessages[i].clear(); - didCloseWirelessRoom = false; } u32 safeStoi(const std::string& str) { diff --git a/lib/LinkWireless.hpp b/lib/LinkWireless.hpp index ebc7641..e63bfbd 100644 --- a/lib/LinkWireless.hpp +++ b/lib/LinkWireless.hpp @@ -37,7 +37,7 @@ // - 6) Send data: // linkWireless->send(0x1234); // - 7) Receive data: -// LinkWireless::Message messages[LINK_WIRELESS_MAX_TRANSFER_LENGTH]; +// LinkWireless::Message messages[LINK_WIRELESS_QUEUE_SIZE]; // linkWireless->receive(messages); // if (messages[0].packetId != LINK_WIRELESS_END) { // // ... @@ -55,6 +55,7 @@ // -------------------------------------------------------------------------- #include +#include #include #include "LinkGPIO.hpp" #include "LinkSPI.hpp" @@ -102,6 +103,7 @@ #define LINK_WIRELESS_RESPONSE_ACK 0x80 #define LINK_WIRELESS_DATA_REQUEST 0x80000000 #define LINK_WIRELESS_SETUP_MAGIC 0x003c0420 +#define LINK_WIRELESS_SETUP_MAX_PLAYERS_BIT 16 #define LINK_WIRELESS_STILL_CONNECTING 0x01000000 #define LINK_WIRELESS_BROADCAST_LENGTH 6 #define LINK_WIRELESS_BROADCAST_RESPONSE_LENGTH \ @@ -116,7 +118,6 @@ #define LINK_WIRELESS_COMMAND_BROADCAST 0x16 #define LINK_WIRELESS_COMMAND_START_HOST 0x19 #define LINK_WIRELESS_COMMAND_ACCEPT_CONNECTIONS 0x1a -#define LINK_WIRELESS_COMMAND_END_HOST 0x1b #define LINK_WIRELESS_COMMAND_BROADCAST_READ_START 0x1c #define LINK_WIRELESS_COMMAND_BROADCAST_READ_POLL 0x1d #define LINK_WIRELESS_COMMAND_BROADCAST_READ_END 0x1e @@ -138,7 +139,7 @@ if (!reset()) \ return false; -static volatile char LINK_WIRELESS_VERSION[] = "LinkWireless/v6.0.2"; +static volatile char LINK_WIRELESS_VERSION[] = "LinkWireless/v6.0.3"; void LINK_WIRELESS_ISR_VBLANK(); void LINK_WIRELESS_ISR_SERIAL(); @@ -203,6 +204,9 @@ class LinkWireless { u16 gameId; std::string gameName; std::string userName; + u8 currentPlayerCount; + + bool isFull() { return currentPlayerCount == 0; } }; explicit LinkWireless( @@ -251,10 +255,9 @@ class LinkWireless { bool serve(std::string gameName = "", std::string userName = "", - u16 gameId = LINK_WIRELESS_MAX_GAME_ID, - bool isUpdate = false) { + u16 gameId = LINK_WIRELESS_MAX_GAME_ID) { LINK_WIRELESS_RESET_IF_NEEDED - if (state != AUTHENTICATED && (!isUpdate || state != SERVING)) { + if (state != AUTHENTICATED && state != SERVING) { lastError = WRONG_STATE; return false; } @@ -269,6 +272,9 @@ class LinkWireless { gameName.append(LINK_WIRELESS_MAX_GAME_NAME_LENGTH - gameName.length(), 0); userName.append(LINK_WIRELESS_MAX_USER_NAME_LENGTH - userName.length(), 0); + if (state != SERVING) + setup(config.maxPlayers); + addData(buildU32(buildU16(gameName[1], gameName[0]), gameId & LINK_WIRELESS_MAX_GAME_ID), true); @@ -285,7 +291,7 @@ class LinkWireless { bool success = sendCommand(LINK_WIRELESS_COMMAND_BROADCAST, true).success; - if (!isUpdate) { + if (state != SERVING) { success = success && sendCommand(LINK_WIRELESS_COMMAND_START_HOST).success; } @@ -382,6 +388,9 @@ class LinkWireless { recoverName(server.gameName, result.responses[start + 4]); recoverName(server.userName, result.responses[start + 5]); recoverName(server.userName, result.responses[start + 6]); + u8 connectedClients = (result.responses[start] >> 16) & 0xff; + server.currentPlayerCount = + connectedClients == 0xff ? 0 : (1 + connectedClients); servers[i] = server; } @@ -476,6 +485,11 @@ class LinkWireless { isAddingMessage = false; LINK_WIRELESS_BARRIER; + if (isPendingClearActive) { + sessionState.tmpMessagesToSend.clear(); + isPendingClearActive = false; + } + return true; } @@ -855,6 +869,7 @@ class LinkWireless { u32 nextCommandDataSize = 0; volatile bool isReadingMessages = false; volatile bool isAddingMessage = false; + volatile bool isPendingClearActive = false; Error lastError = NONE; volatile bool isEnabled = false; @@ -881,21 +896,11 @@ class LinkWireless { switch (asyncCommand.type) { case LINK_WIRELESS_COMMAND_ACCEPT_CONNECTIONS: { // AcceptConnections (end) - u8 oldPlayerCount = sessionState.playerCount; - sessionState.playerCount = 1 + asyncCommand.result.responsesSize; - - if (sessionState.playerCount > oldPlayerCount && - sessionState.playerCount == config.maxPlayers) { - // EndHost (start) - sendCommandAsync(LINK_WIRELESS_COMMAND_END_HOST); - } + sessionState.playerCount = + min(1 + asyncCommand.result.responsesSize, config.maxPlayers); break; } - // case LINK_WIRELESS_COMMAND_END_HOST: { - // // EndHost (end) - // break; - // } case LINK_WIRELESS_COMMAND_SEND_DATA: { // SendData (end) @@ -1239,15 +1244,12 @@ class LinkWireless { return; while (!sessionState.tmpMessagesToSend.isEmpty()) { - if (isSessionActive() && !_canSend()) + if (!_canSend()) break; auto message = sessionState.tmpMessagesToSend.pop(); - - if (isSessionActive()) { - message.packetId = newPacketId(); - sessionState.outgoingMessages.push(message); - } + message.packetId = newPacketId(); + sessionState.outgoingMessages.push(message); } } @@ -1257,9 +1259,7 @@ class LinkWireless { while (!sessionState.tmpMessagesToReceive.isEmpty()) { auto message = sessionState.tmpMessagesToReceive.pop(); - - if (state == SERVING || state == CONNECTED) - sessionState.incomingMessages.push(message); + sessionState.incomingMessages.push(message); } } @@ -1338,6 +1338,12 @@ class LinkWireless { if (!isReadingMessages) this->sessionState.incomingMessages.clear(); this->sessionState.outgoingMessages.clear(); + + this->sessionState.tmpMessagesToReceive.clear(); + if (!isAddingMessage) + this->sessionState.tmpMessagesToSend.clear(); + else + isPendingClearActive = true; } void stop() { @@ -1362,8 +1368,7 @@ class LinkWireless { if (!sendCommand(LINK_WIRELESS_COMMAND_HELLO).success) return false; - addData(LINK_WIRELESS_SETUP_MAGIC, true); - if (!sendCommand(LINK_WIRELESS_COMMAND_SETUP, true).success) + if (!setup()) return false; linkSPI->activate(LinkSPI::Mode::MASTER_2MBPS); @@ -1422,6 +1427,14 @@ class LinkWireless { return true; } + bool setup(u8 maxPlayers = LINK_WIRELESS_MAX_PLAYERS) { + addData(LINK_WIRELESS_SETUP_MAGIC | + (((LINK_WIRELESS_MAX_PLAYERS - maxPlayers) & 0b11) + << LINK_WIRELESS_SETUP_MAX_PLAYERS_BIT), + true); + return sendCommand(LINK_WIRELESS_COMMAND_SETUP, true).success; + } + CommandResult sendCommand(u8 type, bool withData = false) { CommandResult result; u32 command = buildCommand(type, withData ? (u16)nextCommandDataSize : 0); @@ -1599,7 +1612,7 @@ class LinkWireless { bool timeout(u32 limit, u32& lines, u32& vCount) { if (REG_VCOUNT != vCount) { - lines += std::max((int)REG_VCOUNT - (int)vCount, 0); + lines += max((int)REG_VCOUNT - (int)vCount, 0); vCount = REG_VCOUNT; } @@ -1612,7 +1625,7 @@ class LinkWireless { while (count < verticalLines) { if (REG_VCOUNT != vCount) { - count += std::max((int)REG_VCOUNT - (int)vCount, 0); + count++; vCount = REG_VCOUNT; } };