Adding getServersAsync... methods

This commit is contained in:
Rodrigo Alfonso 2023-02-05 20:37:22 -03:00
parent 03fb983073
commit 2fe5d2e946
8 changed files with 86 additions and 44 deletions

View File

@ -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.

View File

@ -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;
}
};

View File

@ -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;
}
};

View File

@ -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();

View File

@ -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;
}
};

View File

@ -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};

View File

@ -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:

View File

@ -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++;
}
}
};
}