Stop using std::queue

This commit is contained in:
Rodrigo Alfonso
2023-02-23 15:21:50 -03:00
parent 2a29d6f680
commit ca6bac223d
3 changed files with 67 additions and 63 deletions

View File

@@ -43,10 +43,12 @@ Name | Type | Default | Description
`baudRate` | **BaudRate** | `BAUD_RATE_1` | Sets a specific baud rate.
`timeout` | **u32** | `3` | Number of *frames* without an `II_SERIAL` IRQ to reset the connection.
`remoteTimeout` | **u32** | `5` | Number of *messages* with `0xFFFF` to mark a player as disconnected.
`bufferSize` | **u32** | `30` | Number of *messages* that the queues will be able to store.
`interval` | **u16** | `50` | Number of *1024cycles* (61.04μs) ticks between messages *(50 = 3.052ms)*. It's the interval of Timer #`sendTimerId`.
`sendTimerId` | **u8** *(0~3)* | `3` | GBA Timer to use for sending.
You can also change these compile-time constants:
- `LINK_CABLE_QUEUE_SIZE`: to set a custom buffer size (how many incoming and outcoming messages the queues can store at max). The default value is `30`, which seems fine for most games.
## Methods
Name | Return type | Description

View File

@@ -37,14 +37,15 @@
// --------------------------------------------------------------------------
#include <tonc_core.h>
#include <queue>
// Buffer size
#define LINK_CABLE_QUEUE_SIZE 30
#define LINK_CABLE_MAX_PLAYERS 4
#define LINK_CABLE_DISCONNECTED 0xFFFF
#define LINK_CABLE_NO_DATA 0x0
#define LINK_CABLE_DEFAULT_TIMEOUT 3
#define LINK_CABLE_DEFAULT_REMOTE_TIMEOUT 5
#define LINK_CABLE_DEFAULT_BUFFER_SIZE 30
#define LINK_CABLE_DEFAULT_INTERVAL 50
#define LINK_CABLE_DEFAULT_SEND_TIMER_ID 3
#define LINK_CABLE_BASE_FREQUENCY TM_FREQ_1024
@@ -67,8 +68,6 @@ static volatile char LINK_CABLE_VERSION[] = "LinkCable/v5.0.1";
void LINK_CABLE_ISR_VBLANK();
void LINK_CABLE_ISR_SERIAL();
void LINK_CABLE_ISR_TIMER();
u16 LINK_CABLE_QUEUE_POP(std::queue<u16>& q);
void LINK_CABLE_QUEUE_CLEAR(std::queue<u16>& q);
const u16 LINK_CABLE_TIMER_IRQ_IDS[] = {IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2,
IRQ_TIMER3};
@@ -81,16 +80,52 @@ class LinkCable {
BAUD_RATE_3 // 115200 bps
};
class U16Queue {
public:
void push(u16 item) {
if (isFull())
pop();
rear = (rear + 1) % LINK_CABLE_QUEUE_SIZE;
arr[rear] = item;
count++;
}
u16 pop() {
if (isEmpty())
return LINK_CABLE_NO_DATA;
auto x = arr[front];
front = (front + 1) % LINK_CABLE_QUEUE_SIZE;
count--;
return x;
}
void clear() {
while (!isEmpty())
pop();
}
int size() { return count; }
bool isEmpty() { return size() == 0; }
bool isFull() { return size() == LINK_CABLE_QUEUE_SIZE; }
private:
u16 arr[LINK_CABLE_QUEUE_SIZE];
vs32 front = 0;
vs32 rear = -1;
vu32 count = 0;
};
explicit LinkCable(BaudRate baudRate = BAUD_RATE_1,
u32 timeout = LINK_CABLE_DEFAULT_TIMEOUT,
u32 remoteTimeout = LINK_CABLE_DEFAULT_REMOTE_TIMEOUT,
u32 bufferSize = LINK_CABLE_DEFAULT_BUFFER_SIZE,
u16 interval = LINK_CABLE_DEFAULT_INTERVAL,
u8 sendTimerId = LINK_CABLE_DEFAULT_SEND_TIMER_ID) {
this->config.baudRate = baudRate;
this->config.timeout = timeout;
this->config.remoteTimeout = remoteTimeout;
this->config.bufferSize = bufferSize;
this->config.interval = interval;
this->config.sendTimerId = sendTimerId;
}
@@ -125,7 +160,7 @@ class LinkCable {
LINK_CABLE_BARRIER;
return !$state.incomingMessages[playerId].empty();
return !$state.incomingMessages[playerId].isEmpty();
}
u16 read(u8 playerId) {
@@ -134,7 +169,7 @@ class LinkCable {
LINK_CABLE_BARRIER;
return LINK_CABLE_QUEUE_POP($state.incomingMessages[playerId]);
return $state.incomingMessages[playerId].pop();
}
void consume() { isStateConsumed = true; }
@@ -147,14 +182,14 @@ class LinkCable {
isAddingMessage = true;
LINK_CABLE_BARRIER;
push(_state.outgoingMessages, data);
_state.outgoingMessages.push(data);
LINK_CABLE_BARRIER;
isAddingMessage = false;
LINK_CABLE_BARRIER;
if (isResetting) {
LINK_CABLE_QUEUE_CLEAR(_state.outgoingMessages);
_state.outgoingMessages.clear();
isResetting = false;
}
}
@@ -189,14 +224,14 @@ class LinkCable {
if (data != LINK_CABLE_DISCONNECTED) {
if (data != LINK_CABLE_NO_DATA && i != state.currentPlayerId)
push(state.incomingMessages[i], data);
state.incomingMessages[i].push(data);
newPlayerCount++;
_state.timeouts[i] = 0;
} else if (_state.timeouts[i] > LINK_CABLE_REMOTE_TIMEOUT_OFFLINE) {
_state.timeouts[i]++;
if (_state.timeouts[i] >= (int)config.remoteTimeout) {
LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]);
state.incomingMessages[i].clear();
_state.timeouts[i] = LINK_CABLE_REMOTE_TIMEOUT_OFFLINE;
} else
newPlayerCount++;
@@ -235,19 +270,18 @@ class LinkCable {
BaudRate baudRate;
u32 timeout;
u32 remoteTimeout;
u32 bufferSize;
u32 interval;
u8 sendTimerId;
};
struct ExternalState {
std::queue<u16> incomingMessages[LINK_CABLE_MAX_PLAYERS];
U16Queue incomingMessages[LINK_CABLE_MAX_PLAYERS];
u8 playerCount;
u8 currentPlayerId;
};
struct InternalState {
std::queue<u16> outgoingMessages;
U16Queue outgoingMessages;
int timeouts[LINK_CABLE_MAX_PLAYERS];
bool IRQFlag;
u32 IRQTimeout;
@@ -275,7 +309,7 @@ class LinkCable {
LINK_CABLE_BARRIER;
transfer(LINK_CABLE_QUEUE_POP(_state.outgoingMessages));
transfer(_state.outgoingMessages.pop());
}
void transfer(u16 data) {
@@ -304,7 +338,7 @@ class LinkCable {
state.playerCount = 0;
state.currentPlayerId = 0;
for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++) {
LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]);
state.incomingMessages[i].clear();
_state.timeouts[i] = LINK_CABLE_REMOTE_TIMEOUT_OFFLINE;
}
_state.IRQFlag = false;
@@ -313,7 +347,7 @@ class LinkCable {
if (isAddingMessage || isResetting)
isResetting = true;
else
LINK_CABLE_QUEUE_CLEAR(_state.outgoingMessages);
_state.outgoingMessages.clear();
}
void stop() {
@@ -352,8 +386,9 @@ class LinkCable {
$state.playerCount = state.playerCount;
$state.currentPlayerId = state.currentPlayerId;
for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++) {
$state.incomingMessages[i].swap(state.incomingMessages[i]);
LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]);
$state.incomingMessages[i].clear();
while (!state.incomingMessages[i].isEmpty())
$state.incomingMessages[i].push(state.incomingMessages[i].pop());
}
LINK_CABLE_BARRIER;
isStateReady = true;
@@ -361,13 +396,6 @@ class LinkCable {
LINK_CABLE_BARRIER;
}
void push(std::queue<u16>& q, u16 value) {
if (q.size() >= config.bufferSize)
LINK_CABLE_QUEUE_POP(q);
q.push(value);
}
bool isBitHigh(u8 bit) { return (REG_SIOCNT >> bit) & 1; }
void setBitHigh(u8 bit) { LINK_CABLE_SET_HIGH(REG_SIOCNT, bit); }
void setBitLow(u8 bit) { LINK_CABLE_SET_LOW(REG_SIOCNT, bit); }
@@ -387,18 +415,4 @@ inline void LINK_CABLE_ISR_TIMER() {
linkCable->_onTimer();
}
inline u16 LINK_CABLE_QUEUE_POP(std::queue<u16>& q) {
if (q.empty())
return LINK_CABLE_NO_DATA;
u16 value = q.front();
q.pop();
return value;
}
inline void LINK_CABLE_QUEUE_CLEAR(std::queue<u16>& q) {
while (!q.empty())
LINK_CABLE_QUEUE_POP(q);
}
#endif // LINK_CABLE_H

View File

@@ -37,14 +37,12 @@
// --------------------------------------------------------------------------
#include <tonc_core.h>
#include <queue>
#include "LinkCable.h"
#include "LinkWireless.h"
#define LINK_UNIVERSAL_MAX_PLAYERS LINK_CABLE_MAX_PLAYERS
#define LINK_UNIVERSAL_DISCONNECTED LINK_CABLE_DISCONNECTED
#define LINK_UNIVERSAL_NO_DATA LINK_CABLE_NO_DATA
#define LINK_UNIVERSAL_BUFFER_SIZE LINK_WIRELESS_QUEUE_SIZE
#define LINK_UNIVERSAL_MAX_ROOM_NUMBER 32000
#define LINK_UNIVERSAL_INIT_WAIT_FRAMES 10
#define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES 25
@@ -94,10 +92,9 @@ class LinkUniversal {
true, LINK_WIRELESS_MAX_PLAYERS, LINK_WIRELESS_DEFAULT_TIMEOUT,
LINK_WIRELESS_DEFAULT_REMOTE_TIMEOUT, LINK_WIRELESS_DEFAULT_INTERVAL,
LINK_WIRELESS_DEFAULT_SEND_TIMER_ID}) {
this->linkCable =
new LinkCable(cableOptions.baudRate, cableOptions.timeout,
cableOptions.remoteTimeout, LINK_UNIVERSAL_BUFFER_SIZE,
cableOptions.interval, cableOptions.sendTimerId);
this->linkCable = new LinkCable(
cableOptions.baudRate, cableOptions.timeout, cableOptions.remoteTimeout,
cableOptions.interval, cableOptions.sendTimerId);
this->linkWireless = new LinkWireless(
wirelessOptions.retransmission, true, wirelessOptions.maxPlayers,
wirelessOptions.timeout, wirelessOptions.remoteTimeout,
@@ -203,11 +200,9 @@ class LinkUniversal {
linkCable->consume();
}
bool canRead(u8 playerId) { return !incomingMessages[playerId].empty(); }
bool canRead(u8 playerId) { return !incomingMessages[playerId].isEmpty(); }
u16 read(u8 playerId) {
return LINK_CABLE_QUEUE_POP(incomingMessages[playerId]);
}
u16 read(u8 playerId) { return incomingMessages[playerId].pop(); }
void send(u16 data) {
if (data == LINK_CABLE_DISCONNECTED || data == LINK_CABLE_NO_DATA)
@@ -258,7 +253,7 @@ class LinkUniversal {
std::string gameName;
};
std::queue<u16> incomingMessages[LINK_UNIVERSAL_MAX_PLAYERS];
LinkCable::U16Queue incomingMessages[LINK_UNIVERSAL_MAX_PLAYERS];
LinkCable* linkCable;
LinkWireless* linkWireless;
Config config;
@@ -273,7 +268,7 @@ class LinkUniversal {
void receiveCableMessages() {
for (u32 i = 0; i < LINK_UNIVERSAL_MAX_PLAYERS; i++) {
while (linkCable->canRead(i))
push(incomingMessages[i], linkCable->read(i));
incomingMessages[i].push(linkCable->read(i));
}
}
@@ -286,7 +281,7 @@ class LinkUniversal {
if (message.packetId == LINK_WIRELESS_END)
break;
push(incomingMessages[message.playerId], message.data);
incomingMessages[message.playerId].push(message.data);
}
}
@@ -438,14 +433,7 @@ class LinkUniversal {
subWaitCount = 0;
serveWait = 0;
for (u32 i = 0; i < LINK_UNIVERSAL_MAX_PLAYERS; i++)
LINK_CABLE_QUEUE_CLEAR(incomingMessages[i]);
}
void push(std::queue<u16>& q, u16 value) {
if (q.size() >= LINK_UNIVERSAL_BUFFER_SIZE)
LINK_CABLE_QUEUE_POP(q);
q.push(value);
incomingMessages[i].clear();
}
};