mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-04-24 23:47:51 -05:00
Adding getServersAsync... methods
This commit is contained in:
parent
03fb983073
commit
2fe5d2e946
16
README.md
16
README.md
|
|
@ -116,8 +116,8 @@ Name | Return type | Description
|
|||
`activate(mode)` | - | Activates the library in a specific `mode` (one of `LinkSPI::Mode::SLAVE`, `LinkSPI::Mode::MASTER_256KBPS`, or `LinkSPI::Mode::MASTER_2MBPS`).
|
||||
`deactivate()` | - | Deactivates the library.
|
||||
`transfer(data)` | **u32** | Exchanges `data` with the other end. Returns the received data.
|
||||
`transfer(data, cancel)` | **u32** | Like `transfer(data)` but accepts a `cancel` function. The library will continuously invoke it, and abort the transfer if it returns `true`.
|
||||
`transferAsync(data, [cancel])` | - | 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!
|
||||
`transfer(data, cancel)` | **u32** | Like `transfer(data)` but accepts a `cancel()` function. The library will continuously invoke it, and abort the transfer if it returns `true`.
|
||||
`transferAsync(data, [cancel])` | - | 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()` | **LinkSPI::AsyncState** | Returns the state of the last async transfer (one of `LinkSPI::AsyncState::IDLE`, `LinkSPI::AsyncState::WAITING`, or `LinkSPI::AsyncState::READY`).
|
||||
`getAsyncData()` | **u32** | If the async state is `READY`, returns the remote data and switches the state back to `IDLE`.
|
||||
`getMode()` | **LinkSPI::Mode** | Returns the current `mode`.
|
||||
|
|
@ -164,20 +164,22 @@ Name | Type | Default | Description
|
|||
Name | Return type | Description
|
||||
--- | --- | ---
|
||||
`isActive()` | **bool** | Returns whether the library is active or not.
|
||||
`activate()` | **bool** | Activates the library.
|
||||
`activate()` | **bool** | Activates the library. When an adapter is connected, it changes the state to `AUTHENTICATED`.
|
||||
`deactivate()` | - | Deactivates the library.
|
||||
`serve([gameName], [userName])` | **bool** | Starts broadcasting a server and changes the state to `SERVING`. You can, optionally, provide a `gameName` (max `14` characters) and `userName` (max `8` characters) that games will be able to read.
|
||||
`acceptConnections()` | **bool** | Accepts new clients and updates the player count.
|
||||
`getServers(servers)` | **bool** | Fills the `servers` vector with all the currently broadcasting servers. This action takes 1 second to complete.
|
||||
`getServers(servers, onWait)` | **bool** | Like `getServers(servers)`, but accepts an `onWait()` function. The library will continuously invoke it each time VBlank starts, to let the user do something while waiting (like updating the screen).
|
||||
`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` vector with all the currently broadcasting servers. Changes the state to `AUTHENTICATED` again.
|
||||
`connect(serverId)` | **bool** | Starts a connection with `serverId` and changes the state to `CONNECTING`.
|
||||
`keepConnecting()` | **bool** | When connecting, needs to be called until the state is `CONNECTED`. It assigns a player id.
|
||||
`getServers(servers)` | **bool** | Fills the `servers` vector with all the currently broadcasting servers. This action takes 1 second to complete.
|
||||
`getServers(servers, onWait)` | **bool** | Like `getServers(servers)`, but accepts an `onWait` function. The library will continuously invoke it each time VBlank starts, to let the user do something while waiting (like updating the screen).
|
||||
`send(data)` | **bool** | Enqueues `data` to be sent to other nodes. Note that this data will be sent in the next `receive(...)` call.
|
||||
`receive(messages)` | **bool** | Sends the pending data and fills the `messages` vector with incoming messages, checking for timeouts and forwarding if needed. This call doesn't block the hardware waiting for messages, it returns if there are no incoming messages.
|
||||
`receive(messages, times)` | **bool** | Performs multiple `receive(...)` calls until successfully exchanging data a number of `times`. This can only be called if `retransmission` is on.
|
||||
`receive(messages, times, cancel)` | **bool** | Like `receive(messages, times)` but accepts a `cancel` function. The library will continuously invoke it, and abort the transfer if it returns `true`.
|
||||
`receive(messages, times, cancel)` | **bool** | Like `receive(messages, times)` but accepts a `cancel()` function. The library will continuously invoke it, and abort the transfer if it returns `true`.
|
||||
`disconnect()` | **bool** | Disconnects and resets the adapter.
|
||||
`getState()` | **LinkWireless::State** | Returns the current state (one of `LinkWireless::State::NEEDS_RESET`, `LinkWireless::State::AUTHENTICATED`, `LinkWireless::State::SERVING`, `LinkWireless::State::CONNECTING`, or `LinkWireless::State::CONNECTED`).
|
||||
`getState()` | **LinkWireless::State** | Returns the current state (one of `LinkWireless::State::NEEDS_RESET`, `LinkWireless::State::AUTHENTICATED`, `LinkWireless::State::SEARCHING`, `LinkWireless::State::SERVING`, `LinkWireless::State::CONNECTING`, or `LinkWireless::State::CONNECTED`).
|
||||
`getPlayerId()` | **u8** *(0~4)* | Returns the current player id.
|
||||
`getPlayerCount()` | **u8** *(1~5)* | Returns the connected players.
|
||||
`canSend()` | **bool** | Returns `false` only if the next `send(...)` call would fail due to full buffers.
|
||||
|
|
|
|||
|
|
@ -36,12 +36,12 @@ inline void SCENE_write(std::string text, u32 row) {
|
|||
}
|
||||
|
||||
inline void SCENE_wait(u32 verticalLines) {
|
||||
u32 lines = 0;
|
||||
u32 count = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (lines < verticalLines) {
|
||||
while (count < verticalLines) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
lines++;
|
||||
count++;
|
||||
vCount = REG_VCOUNT;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -114,12 +114,12 @@ void log(std::string text) {
|
|||
}
|
||||
|
||||
void wait(u32 verticalLines) {
|
||||
u32 lines = 0;
|
||||
u32 count = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (lines < verticalLines) {
|
||||
while (count < verticalLines) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
lines++;
|
||||
count++;
|
||||
vCount = REG_VCOUNT;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
#define LINK_CABLE_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_CABLE_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
|
||||
static volatile char LINK_CABLE_VERSION[] = "LinkCable/v4.2.0";
|
||||
static volatile char LINK_CABLE_VERSION[] = "LinkCable/v4.3.0";
|
||||
|
||||
void LINK_CABLE_ISR_VBLANK();
|
||||
void LINK_CABLE_ISR_TIMER();
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
return error(FAILURE_DURING_HANDSHAKE);
|
||||
|
||||
static volatile char LINK_CABLE_MULTIBOOT_VERSION[] =
|
||||
"LinkCableMultiboot/v4.2.0";
|
||||
"LinkCableMultiboot/v4.3.0";
|
||||
|
||||
const u8 LINK_CABLE_MULTIBOOT_CLIENT_IDS[] = {0b0010, 0b0100, 0b1000};
|
||||
|
||||
|
|
@ -294,12 +294,12 @@ class LinkCableMultiboot {
|
|||
}
|
||||
|
||||
void wait(u32 verticalLines) {
|
||||
u32 lines = 0;
|
||||
u32 count = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (lines < verticalLines) {
|
||||
while (count < verticalLines) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
lines++;
|
||||
count++;
|
||||
vCount = REG_VCOUNT;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#define LINK_GPIO_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_GPIO_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
|
||||
static volatile char LINK_GPIO_VERSION[] = "LinkGPIO/v4.2.0";
|
||||
static volatile char LINK_GPIO_VERSION[] = "LinkGPIO/v4.3.0";
|
||||
|
||||
const u8 LINK_GPIO_DATA_BITS[] = {2, 3, 1, 0};
|
||||
const u8 LINK_GPIO_DIRECTION_BITS[] = {6, 7, 5, 4};
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
#define LINK_SPI_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_SPI_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
|
||||
static volatile char LINK_SPI_VERSION[] = "LinkSPI/v4.2.0";
|
||||
static volatile char LINK_SPI_VERSION[] = "LinkSPI/v4.3.0";
|
||||
|
||||
class LinkSPI {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
#define LINK_WIRELESS_MSG_CONFIRMATION 0
|
||||
#define LINK_WIRELESS_PING_WAIT 50
|
||||
#define LINK_WIRELESS_TRANSFER_WAIT 15
|
||||
#define LINK_WIRELESS_BROADCAST_SEARCH_WAIT ((160 + 68) * 60)
|
||||
#define LINK_WIRELESS_BROADCAST_SEARCH_WAIT_FRAMES 60
|
||||
#define LINK_WIRELESS_CMD_TIMEOUT 100
|
||||
#define LINK_WIRELESS_MIN_PLAYERS 2
|
||||
#define LINK_WIRELESS_MAX_PLAYERS 5
|
||||
|
|
@ -91,7 +91,7 @@
|
|||
if (state == NEEDS_RESET) \
|
||||
reset();
|
||||
|
||||
static volatile char LINK_WIRELESS_VERSION[] = "LinkWireless/v4.2.0";
|
||||
static volatile char LINK_WIRELESS_VERSION[] = "LinkWireless/v4.3.0";
|
||||
|
||||
const u16 LINK_WIRELESS_LOGIN_PARTS[] = {0x494e, 0x494e, 0x544e, 0x544e, 0x4e45,
|
||||
0x4e45, 0x4f44, 0x4f44, 0x8001};
|
||||
|
|
@ -100,7 +100,14 @@ const u32 LINK_WIRELESS_USER_MAX_CLIENT_TRANSFER_LENGTHS[] = {3, 1};
|
|||
|
||||
class LinkWireless {
|
||||
public:
|
||||
enum State { NEEDS_RESET, AUTHENTICATED, SERVING, CONNECTING, CONNECTED };
|
||||
enum State {
|
||||
NEEDS_RESET,
|
||||
AUTHENTICATED,
|
||||
SEARCHING,
|
||||
SERVING,
|
||||
CONNECTING,
|
||||
CONNECTED
|
||||
};
|
||||
|
||||
enum Error {
|
||||
// User errors
|
||||
|
|
@ -243,38 +250,60 @@ class LinkWireless {
|
|||
|
||||
template <typename F>
|
||||
bool getServers(std::vector<Server>& servers, F onWait) {
|
||||
if (!getServersAsyncStart())
|
||||
return false;
|
||||
|
||||
waitVBlanks(LINK_WIRELESS_BROADCAST_SEARCH_WAIT_FRAMES, onWait);
|
||||
|
||||
if (!getServersAsyncEnd(servers))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getServersAsyncStart() {
|
||||
LINK_WIRELESS_RESET_IF_NEEDED
|
||||
if (state != AUTHENTICATED) {
|
||||
lastError = WRONG_STATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success1 =
|
||||
bool success =
|
||||
sendCommand(LINK_WIRELESS_COMMAND_BROADCAST_READ_START).success;
|
||||
|
||||
if (!success) {
|
||||
reset();
|
||||
lastError = COMMAND_FAILED;
|
||||
return false;
|
||||
}
|
||||
|
||||
state = SEARCHING;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getServersAsyncEnd(std::vector<Server>& servers) {
|
||||
LINK_WIRELESS_RESET_IF_NEEDED
|
||||
if (state != SEARCHING) {
|
||||
lastError = WRONG_STATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = sendCommand(LINK_WIRELESS_COMMAND_BROADCAST_READ_POLL);
|
||||
bool success1 =
|
||||
result.success &&
|
||||
result.responses.size() % LINK_WIRELESS_BROADCAST_RESPONSE_LENGTH == 0;
|
||||
|
||||
if (!success1) {
|
||||
reset();
|
||||
lastError = COMMAND_FAILED;
|
||||
return false;
|
||||
}
|
||||
|
||||
wait(LINK_WIRELESS_BROADCAST_SEARCH_WAIT, onWait);
|
||||
|
||||
auto result = sendCommand(LINK_WIRELESS_COMMAND_BROADCAST_READ_POLL);
|
||||
bool success2 =
|
||||
result.success &&
|
||||
result.responses.size() % LINK_WIRELESS_BROADCAST_RESPONSE_LENGTH == 0;
|
||||
|
||||
if (!success2) {
|
||||
reset();
|
||||
lastError = COMMAND_FAILED;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success3 =
|
||||
sendCommand(LINK_WIRELESS_COMMAND_BROADCAST_READ_END).success;
|
||||
|
||||
if (!success3) {
|
||||
if (!success2) {
|
||||
reset();
|
||||
lastError = COMMAND_FAILED;
|
||||
return false;
|
||||
|
|
@ -298,6 +327,8 @@ class LinkWireless {
|
|||
servers.push_back(server);
|
||||
}
|
||||
|
||||
state = AUTHENTICATED;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -973,21 +1004,30 @@ class LinkWireless {
|
|||
}
|
||||
|
||||
void wait(u32 verticalLines) {
|
||||
wait(verticalLines, []() {});
|
||||
u32 count = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (count < verticalLines) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
count += std::max((s32)REG_VCOUNT - (s32)vCount, 0);
|
||||
vCount = REG_VCOUNT;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void wait(u32 verticalLines, F onVBlank) {
|
||||
u32 lines = 0;
|
||||
void waitVBlanks(u32 vBlanks, F onVBlank) {
|
||||
u32 count = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (lines < verticalLines) {
|
||||
while (count < vBlanks) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
lines += std::max((s32)REG_VCOUNT - (s32)vCount, 0);
|
||||
vCount = REG_VCOUNT;
|
||||
|
||||
if (REG_VCOUNT == 160)
|
||||
if (vCount == 160) {
|
||||
onVBlank();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user