mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-04-26 02:02:25 -05:00
LinkWireless: Using SignalLevel (0x11) instead of AcceptConnections (0x1a) to update player count
This commit is contained in:
parent
7040f03087
commit
87748c6714
|
|
@ -248,7 +248,7 @@ You can also change these compile-time constants:
|
|||
| `deactivate([turnOff])` | **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. You can disable the transition and deactivate directly by setting `turnOff` to `true`. |
|
||||
| `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. The strings must be null-terminated character arrays. If the adapter is already serving, this method only updates the broadcast data. Updating broadcast data while serving can fail if the adapter is busy. In that case, this will return `false` and `getLastError()` will be `BUSY_TRY_AGAIN`. |
|
||||
| `closeServer()` | **bool** | Closes the server while keeping the session active, to prevent new users from joining the room. This action can fail if the adapter is busy. In that case, this will return `false` and `getLastError()` will be `BUSY_TRY_AGAIN`. |
|
||||
| `getSignalLevel(response)` | **bool** | Retrieves the signal level of each player (0-255), filling the `response` struct. For hosts, the array will contain the signal level of each client in indexes 1-4. For clients, it will only include the index corresponding to the `currentPlayerId()`. This action can fail if the adapter is busy. In that case, this will return `false` and `getLastError()` will be `BUSY_TRY_AGAIN`. |
|
||||
| `getSignalLevel(response)` | **bool** | Retrieves the signal level of each player (0-255), filling the `response` struct. For hosts, the array will contain the signal level of each client in indexes 1-4. For clients, it will only include the index corresponding to the `currentPlayerId()`. On clients, this action can fail if the adapter is busy. In that case, this will return `false` and `getLastError()` will be `BUSY_TRY_AGAIN`. |
|
||||
| `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. |
|
||||
|
|
|
|||
|
|
@ -65,11 +65,11 @@
|
|||
|
||||
static volatile char LINK_CABLE_VERSION[] = "LinkCable/v8.0.0";
|
||||
|
||||
#define LINK_CABLE_MAX_PLAYERS 4
|
||||
#define LINK_CABLE_MAX_PLAYERS LINK_RAW_CABLE_MAX_PLAYERS
|
||||
#define LINK_CABLE_DEFAULT_TIMEOUT 3
|
||||
#define LINK_CABLE_DEFAULT_INTERVAL 50
|
||||
#define LINK_CABLE_DEFAULT_SEND_TIMER_ID 3
|
||||
#define LINK_CABLE_DISCONNECTED 0xffff
|
||||
#define LINK_CABLE_DISCONNECTED LINK_RAW_CABLE_DISCONNECTED
|
||||
#define LINK_CABLE_NO_DATA 0x0
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1557,16 +1557,16 @@ class LinkMobile {
|
|||
void resetState() {
|
||||
setState(NEEDS_RESET);
|
||||
|
||||
this->adapterConfiguration = AdapterConfiguration{};
|
||||
this->userRequests.clear();
|
||||
this->asyncCommand.reset();
|
||||
this->waitFrames = 0;
|
||||
this->timeoutStateFrames = 0;
|
||||
this->role = Role::NO_P2P_CONNECTION;
|
||||
this->nextCommandDataSize = 0;
|
||||
this->hasPendingTransfer = false;
|
||||
this->pendingTransfer = 0;
|
||||
this->adapterType = AdapterType::UNKNOWN;
|
||||
adapterConfiguration = AdapterConfiguration{};
|
||||
userRequests.clear();
|
||||
asyncCommand.reset();
|
||||
waitFrames = 0;
|
||||
timeoutStateFrames = 0;
|
||||
role = Role::NO_P2P_CONNECTION;
|
||||
nextCommandDataSize = 0;
|
||||
hasPendingTransfer = false;
|
||||
pendingTransfer = 0;
|
||||
adapterType = AdapterType::UNKNOWN;
|
||||
|
||||
userRequests.syncClear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ static volatile char LINK_RAW_WIRELESS_VERSION[] = "LinkRawWireless/v8.0.0";
|
|||
#define LINK_RAW_WIRELESS_MAX_GAME_NAME_LENGTH 14
|
||||
#define LINK_RAW_WIRELESS_MAX_USER_NAME_LENGTH 8
|
||||
#define LINK_RAW_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH 23
|
||||
#define LINK_RAW_WIRELESS_BROADCAST_LENGTH 6
|
||||
#define LINK_RAW_WIRELESS_BROADCAST_RESPONSE_LENGTH \
|
||||
(1 + LINK_RAW_WIRELESS_BROADCAST_LENGTH)
|
||||
#define LINK_RAW_WIRELESS_MAX_SERVERS \
|
||||
(LINK_RAW_WIRELESS_MAX_COMMAND_RESPONSE_LENGTH / \
|
||||
LINK_RAW_WIRELESS_BROADCAST_LENGTH)
|
||||
|
||||
#ifdef LINK_RAW_WIRELESS_ENABLE_LOGGING
|
||||
#include <string>
|
||||
|
|
@ -98,10 +104,6 @@ class LinkRawWireless {
|
|||
static constexpr u32 DATA_REQUEST_VALUE = 0x80000000;
|
||||
static constexpr int SETUP_MAGIC = 0x003c0000;
|
||||
static constexpr int WAIT_STILL_CONNECTING = 0x01000000;
|
||||
static constexpr int BROADCAST_LENGTH = 6;
|
||||
static constexpr int BROADCAST_RESPONSE_LENGTH = 1 + BROADCAST_LENGTH;
|
||||
static constexpr int MAX_SERVERS =
|
||||
LINK_RAW_WIRELESS_MAX_COMMAND_RESPONSE_LENGTH / BROADCAST_RESPONSE_LENGTH;
|
||||
static constexpr int COMMAND_HELLO = 0x10;
|
||||
static constexpr int COMMAND_SETUP = 0x17;
|
||||
static constexpr int COMMAND_SYSTEM_STATUS = 0x13;
|
||||
|
|
@ -188,7 +190,7 @@ class LinkRawWireless {
|
|||
};
|
||||
|
||||
struct BroadcastReadPollResponse {
|
||||
Server servers[MAX_SERVERS] = {};
|
||||
Server servers[LINK_RAW_WIRELESS_MAX_SERVERS] = {};
|
||||
u32 serversSize = 0;
|
||||
};
|
||||
|
||||
|
|
@ -391,7 +393,7 @@ class LinkRawWireless {
|
|||
copyName(finalGameName, gameName, LINK_RAW_WIRELESS_MAX_GAME_NAME_LENGTH);
|
||||
copyName(finalUserName, userName, LINK_RAW_WIRELESS_MAX_USER_NAME_LENGTH);
|
||||
|
||||
u32 params[BROADCAST_LENGTH] = {
|
||||
u32 params[LINK_RAW_WIRELESS_BROADCAST_LENGTH] = {
|
||||
Link::buildU32(Link::buildU16(finalGameName[1], finalGameName[0]),
|
||||
gameId),
|
||||
Link::buildU32(Link::buildU16(finalGameName[5], finalGameName[4]),
|
||||
|
|
@ -404,8 +406,9 @@ class LinkRawWireless {
|
|||
Link::buildU16(finalUserName[1], finalUserName[0])),
|
||||
Link::buildU32(Link::buildU16(finalUserName[7], finalUserName[6]),
|
||||
Link::buildU16(finalUserName[5], finalUserName[4]))};
|
||||
bool success =
|
||||
sendCommand(COMMAND_BROADCAST, params, BROADCAST_LENGTH).success;
|
||||
bool success = sendCommand(COMMAND_BROADCAST, params,
|
||||
LINK_RAW_WIRELESS_BROADCAST_LENGTH)
|
||||
.success;
|
||||
|
||||
if (!success) {
|
||||
_resetState();
|
||||
|
|
@ -570,18 +573,20 @@ class LinkRawWireless {
|
|||
bool broadcastReadPoll(BroadcastReadPollResponse& response) {
|
||||
auto result = sendCommand(COMMAND_BROADCAST_READ_POLL);
|
||||
bool success =
|
||||
result.success && result.dataSize % BROADCAST_RESPONSE_LENGTH == 0;
|
||||
result.success &&
|
||||
result.dataSize % LINK_RAW_WIRELESS_BROADCAST_RESPONSE_LENGTH == 0;
|
||||
|
||||
if (!success) {
|
||||
_resetState();
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 totalBroadcasts = result.dataSize / BROADCAST_RESPONSE_LENGTH;
|
||||
u32 totalBroadcasts =
|
||||
result.dataSize / LINK_RAW_WIRELESS_BROADCAST_RESPONSE_LENGTH;
|
||||
|
||||
response.serversSize = 0;
|
||||
for (u32 i = 0; i < totalBroadcasts; i++) {
|
||||
u32 start = BROADCAST_RESPONSE_LENGTH * i;
|
||||
u32 start = LINK_RAW_WIRELESS_BROADCAST_RESPONSE_LENGTH * i;
|
||||
|
||||
Server server;
|
||||
server.id = (u16)result.data[start];
|
||||
|
|
|
|||
|
|
@ -137,17 +137,10 @@
|
|||
|
||||
static volatile char LINK_WIRELESS_VERSION[] = "LinkWireless/v8.0.0";
|
||||
|
||||
#define LINK_WIRELESS_MAX_PLAYERS 5
|
||||
#define LINK_WIRELESS_MAX_PLAYERS LINK_RAW_WIRELESS_MAX_PLAYERS
|
||||
#define LINK_WIRELESS_MIN_PLAYERS 2
|
||||
#define LINK_WIRELESS_END 0
|
||||
#define LINK_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH 22
|
||||
#define LINK_WIRELESS_MAX_COMMAND_RESPONSE_LENGTH 30
|
||||
#define LINK_WIRELESS_BROADCAST_LENGTH 6
|
||||
#define LINK_WIRELESS_BROADCAST_RESPONSE_LENGTH \
|
||||
(1 + LINK_WIRELESS_BROADCAST_LENGTH)
|
||||
#define LINK_WIRELESS_MAX_SERVERS \
|
||||
(LINK_WIRELESS_MAX_COMMAND_RESPONSE_LENGTH / \
|
||||
LINK_WIRELESS_BROADCAST_RESPONSE_LENGTH)
|
||||
#define LINK_WIRELESS_MAX_SERVERS LINK_RAW_WIRELESS_MAX_SERVERS
|
||||
#define LINK_WIRELESS_MAX_GAME_ID 0x7fff
|
||||
#define LINK_WIRELESS_MAX_GAME_NAME_LENGTH 14
|
||||
#define LINK_WIRELESS_MAX_USER_NAME_LENGTH 8
|
||||
|
|
@ -170,9 +163,10 @@ class LinkWireless {
|
|||
using u32 = Link::u32;
|
||||
using u16 = Link::u16;
|
||||
using u8 = Link::u8;
|
||||
using s8 = Link::s8;
|
||||
using vu32 = Link::vu32;
|
||||
using vs32 = Link::vs32;
|
||||
using s8 = Link::s8;
|
||||
using vu8 = Link::vu8;
|
||||
|
||||
static constexpr auto BASE_FREQUENCY = Link::_TM_FREQ_1024;
|
||||
#ifdef LINK_WIRELESS_TWO_PLAYERS_ONLY
|
||||
|
|
@ -184,6 +178,7 @@ class LinkWireless {
|
|||
static constexpr int PACKET_ID_MASK = (MAX_PACKET_IDS - 1);
|
||||
static constexpr int MSG_PING = 0xffff;
|
||||
static constexpr int BROADCAST_SEARCH_WAIT_FRAMES = 60;
|
||||
static constexpr int MAX_COMMAND_TRANSFER_LENGTH = 22;
|
||||
|
||||
public:
|
||||
#ifdef LINK_WIRELESS_TWO_PLAYERS_ONLY
|
||||
|
|
@ -239,6 +234,10 @@ class LinkWireless {
|
|||
bool isFull() { return currentPlayerCount == 0; }
|
||||
};
|
||||
|
||||
struct SignalLevel {
|
||||
vu8 level[LINK_WIRELESS_MAX_PLAYERS] = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructs a new LinkWireless object.
|
||||
* @param forwarding If `true`, the server forwards all messages to the
|
||||
|
|
@ -378,8 +377,11 @@ class LinkWireless {
|
|||
|
||||
bool success = linkRawWireless.broadcast(gameName, userName, gameId, false);
|
||||
|
||||
if (linkRawWireless.getState() != State::SERVING)
|
||||
success = success && linkRawWireless.startHost();
|
||||
if (linkRawWireless.getState() != State::SERVING) {
|
||||
LinkRawWireless::AcceptConnectionsResponse response;
|
||||
success = success && linkRawWireless.startHost() &&
|
||||
linkRawWireless.acceptConnections(response);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
return abort(COMMAND_FAILED);
|
||||
|
|
@ -426,14 +428,21 @@ class LinkWireless {
|
|||
* clients, it will only include the index corresponding to the
|
||||
* `currentPlayerId()`.
|
||||
* @param response A structure that will be filled with the signal levels.
|
||||
* \warning This action can fail if the adapter is busy. In that case, this
|
||||
* will return `false` and `getLastError()` will be `BUSY_TRY_AGAIN`.
|
||||
* \warning On clients, this action can fail if the adapter is busy. In that
|
||||
* case, this will return `false` and `getLastError()` will be
|
||||
* `BUSY_TRY_AGAIN`.
|
||||
*/
|
||||
bool getSignalLevel(SignalLevelResponse& response) {
|
||||
LINK_WIRELESS_RESET_IF_NEEDED
|
||||
if (!isSessionActive())
|
||||
return badRequest(WRONG_STATE);
|
||||
|
||||
if (linkRawWireless.getState() == LinkRawWireless::State::SERVING) {
|
||||
for (u32 i = 0; i < LINK_WIRELESS_MAX_PLAYERS; i++)
|
||||
response.signalLevels[i] = sessionState.signalLevel.level[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
isSendingSyncCommand = true;
|
||||
if (isAsyncCommandActive())
|
||||
return badRequest(BUSY_TRY_AGAIN);
|
||||
|
|
@ -827,7 +836,7 @@ class LinkWireless {
|
|||
#endif
|
||||
|
||||
sessionState.recvFlag = false;
|
||||
sessionState.acceptCalled = false;
|
||||
sessionState.signalLevelCalled = false;
|
||||
sessionState.pingSent = false;
|
||||
|
||||
#ifdef LINK_WIRELESS_PROFILING_ENABLED
|
||||
|
|
@ -886,7 +895,7 @@ class LinkWireless {
|
|||
return;
|
||||
|
||||
if (!isAsyncCommandActive())
|
||||
acceptConnectionsOrTransferData();
|
||||
checkConnectionsOrTransferData();
|
||||
|
||||
#ifdef LINK_WIRELESS_PROFILING_ENABLED
|
||||
timerTime += profileStop();
|
||||
|
|
@ -917,13 +926,14 @@ class LinkWireless {
|
|||
MessageQueue outgoingMessages; // read and write by irq
|
||||
MessageQueue newIncomingMessages; // read and write by irq
|
||||
MessageQueue newOutgoingMessages; // read by irq, write by user&irq
|
||||
SignalLevel signalLevel; // write by irq, read by any
|
||||
|
||||
u32 recvTimeout = 0; // (~= LinkCable::IRQTimeout)
|
||||
u32 msgTimeouts[LINK_WIRELESS_MAX_PLAYERS]; // (~= LinkCable::msgTimeouts)
|
||||
bool recvFlag = false; // (~= LinkCable::IRQFlag)
|
||||
bool msgFlags[LINK_WIRELESS_MAX_PLAYERS]; // (~= LinkCable::msgFlags)
|
||||
|
||||
bool acceptCalled = false;
|
||||
bool signalLevelCalled = false;
|
||||
bool pingSent = false;
|
||||
#ifdef LINK_WIRELESS_USE_SEND_RECEIVE_LATCH
|
||||
bool sendReceiveLatch = false; // true = send ; false = receive
|
||||
|
|
@ -960,7 +970,7 @@ class LinkWireless {
|
|||
|
||||
LinkRawWireless linkRawWireless;
|
||||
SessionState sessionState;
|
||||
u32 nextAsyncCommandData[LINK_WIRELESS_MAX_COMMAND_TRANSFER_LENGTH];
|
||||
u32 nextAsyncCommandData[MAX_COMMAND_TRANSFER_LENGTH];
|
||||
u32 nextAsyncCommandDataSize = 0;
|
||||
volatile bool isSendingSyncCommand = false;
|
||||
volatile Error lastError = NONE;
|
||||
|
|
@ -1008,10 +1018,21 @@ class LinkWireless {
|
|||
}
|
||||
|
||||
switch (commandResult->commandId) {
|
||||
case LinkRawWireless::COMMAND_ACCEPT_CONNECTIONS: {
|
||||
// AcceptConnections (end)
|
||||
linkRawWireless.sessionState.playerCount =
|
||||
Link::_min(1 + commandResult->dataSize, config.maxPlayers);
|
||||
case LinkRawWireless::COMMAND_SIGNAL_LEVEL: {
|
||||
// SignalLevel (end)
|
||||
u32 levels = commandResult->dataSize > 0 ? commandResult->data[0] : 0;
|
||||
u32 players = 1;
|
||||
for (u32 i = 1; i < LINK_WIRELESS_MAX_PLAYERS; i++) {
|
||||
u32 level = (levels >> ((i - 1) * 8)) & 0xff;
|
||||
sessionState.signalLevel.level[i] = level;
|
||||
if (level > 0)
|
||||
players++;
|
||||
}
|
||||
|
||||
if (players > linkRawWireless.sessionState.playerCount) {
|
||||
linkRawWireless.sessionState.playerCount =
|
||||
Link::_min(players, config.maxPlayers);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -1065,14 +1086,14 @@ class LinkWireless {
|
|||
}
|
||||
}
|
||||
|
||||
LINK_INLINE void acceptConnectionsOrTransferData() { // (irq only)
|
||||
LINK_INLINE void checkConnectionsOrTransferData() { // (irq only)
|
||||
if (linkRawWireless.getState() == State::SERVING &&
|
||||
!linkRawWireless.sessionState.isServerClosed &&
|
||||
!sessionState.acceptCalled &&
|
||||
!sessionState.signalLevelCalled &&
|
||||
linkRawWireless.sessionState.playerCount < config.maxPlayers) {
|
||||
// AcceptConnections (start)
|
||||
if (sendCommandAsync(LinkRawWireless::COMMAND_ACCEPT_CONNECTIONS))
|
||||
sessionState.acceptCalled = true;
|
||||
// SignalLevel (start)
|
||||
if (sendCommandAsync(LinkRawWireless::COMMAND_SIGNAL_LEVEL))
|
||||
sessionState.signalLevelCalled = true;
|
||||
} else if (linkRawWireless.getState() == State::CONNECTED ||
|
||||
isConnected()) {
|
||||
#ifdef LINK_WIRELESS_USE_SEND_RECEIVE_LATCH
|
||||
|
|
@ -1458,33 +1479,34 @@ class LinkWireless {
|
|||
QUICK_SEND = 0;
|
||||
QUICK_RECEIVE = 0;
|
||||
#endif
|
||||
this->sessionState.recvFlag = false;
|
||||
this->sessionState.recvTimeout = 0;
|
||||
this->sessionState.acceptCalled = false;
|
||||
this->sessionState.pingSent = false;
|
||||
sessionState.recvFlag = false;
|
||||
sessionState.recvTimeout = 0;
|
||||
sessionState.signalLevelCalled = false;
|
||||
sessionState.pingSent = false;
|
||||
#ifdef LINK_WIRELESS_USE_SEND_RECEIVE_LATCH
|
||||
this->sessionState.sendReceiveLatch = false;
|
||||
this->sessionState.shouldWaitForServer = false;
|
||||
sessionState.sendReceiveLatch = false;
|
||||
sessionState.shouldWaitForServer = false;
|
||||
#endif
|
||||
this->sessionState.didReceiveLastPacketIdFromServer = false;
|
||||
this->sessionState.lastPacketId = 0;
|
||||
this->sessionState.lastPacketIdFromServer = 0;
|
||||
this->sessionState.lastConfirmationFromServer = 0;
|
||||
sessionState.didReceiveLastPacketIdFromServer = false;
|
||||
sessionState.lastPacketId = 0;
|
||||
sessionState.lastPacketIdFromServer = 0;
|
||||
sessionState.lastConfirmationFromServer = 0;
|
||||
for (u32 i = 0; i < LINK_WIRELESS_MAX_PLAYERS; i++) {
|
||||
this->sessionState.msgTimeouts[i] = 0;
|
||||
this->sessionState.msgFlags[i] = false;
|
||||
this->sessionState.lastPacketIdFromClients[i] = 0;
|
||||
this->sessionState.lastConfirmationFromClients[i] = 0;
|
||||
sessionState.msgTimeouts[i] = 0;
|
||||
sessionState.msgFlags[i] = false;
|
||||
sessionState.lastPacketIdFromClients[i] = 0;
|
||||
sessionState.lastConfirmationFromClients[i] = 0;
|
||||
}
|
||||
this->nextAsyncCommandDataSize = 0;
|
||||
nextAsyncCommandDataSize = 0;
|
||||
|
||||
this->sessionState.incomingMessages.syncClear();
|
||||
this->sessionState.outgoingMessages.clear();
|
||||
sessionState.incomingMessages.syncClear();
|
||||
sessionState.outgoingMessages.clear();
|
||||
|
||||
this->sessionState.newIncomingMessages.clear();
|
||||
this->sessionState.newOutgoingMessages.syncClear();
|
||||
sessionState.newIncomingMessages.clear();
|
||||
sessionState.newOutgoingMessages.syncClear();
|
||||
|
||||
this->sessionState.newIncomingMessages.overflow = false;
|
||||
sessionState.newIncomingMessages.overflow = false;
|
||||
sessionState.signalLevel = SignalLevel{};
|
||||
|
||||
isSendingSyncCommand = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user