Organizing ISR functions

This commit is contained in:
Rodrigo Alfonso 2025-02-05 01:54:23 -03:00
parent 8e17f9a1a2
commit 6055e4faac
2 changed files with 177 additions and 159 deletions

View File

@ -1,8 +1,5 @@
#include "LinkWireless.hpp"
#if defined(LINK_WIRELESS_PUT_ISR_IN_IWRAM) || \
defined(LINK_WIRELESS_ENABLE_NESTED_IRQ)
#ifdef LINK_WIRELESS_PUT_ISR_IN_IWRAM
#if LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL == 1
@ -21,37 +18,21 @@
#define _LINK_TIMER_ISR
#endif
#endif
_LINK_SERIAL_ISR void LinkWireless::_onSerial() {
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
interrupt = true;
LINK_BARRIER;
// (nested interrupts are enabled by LinkRawWireless::_onSerial(...))
#endif
__onSerial();
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
irqEnd();
#endif
}
_LINK_TIMER_ISR void LinkWireless::_onTimer() {
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
if (interrupt)
return;
interrupt = true;
LINK_BARRIER;
Link::_REG_IME = 1;
#endif
__onTimer();
}
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
irqEnd();
#endif
_LINK_SERIAL_ISR void LinkWireless::processMessage(u32 playerId,
u32 data,
u32& currentPacketId,
u32& playerBitMap,
int& playerBitMapCount) {
_processMessage(playerId, data, currentPacketId, playerBitMap,
playerBitMapCount);
}
/**

View File

@ -114,6 +114,21 @@
// #define LINK_WIRELESS_ENABLE_NESTED_IRQ
#endif
// --- LINK_WIRELESS_PUT_ISR_IN_IWRAM knobs ---
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL 1
#endif
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER 0
#endif
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL_LEVEL
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL_LEVEL "-Ofast"
#endif
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER_LEVEL
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER_LEVEL "-Ofast"
#endif
//---
LINK_VERSION_TAG LINK_WIRELESS_VERSION = "vLinkWireless/v8.0.0";
#define LINK_WIRELESS_MAX_PLAYERS LINK_RAW_WIRELESS_MAX_PLAYERS
@ -133,19 +148,6 @@ LINK_VERSION_TAG LINK_WIRELESS_VERSION = "vLinkWireless/v8.0.0";
if (!reset()) \
return false;
// --- LINK_WIRELESS_PUT_ISR_IN_IWRAM knobs ---
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL 1
#endif
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER 0
#endif
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL_LEVEL
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL_LEVEL "-Ofast"
#endif
#ifndef LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER_LEVEL
#define LINK_WIRELESS_PUT_ISR_IN_IWRAM_TIMER_LEVEL "-Ofast"
#endif
#ifdef LINK_WIRELESS_PUT_ISR_IN_IWRAM
#if LINK_WIRELESS_PUT_ISR_IN_IWRAM_SERIAL == 1
#define LINK_WIRELESS_SERIAL_ISR LINK_INLINE
@ -157,11 +159,19 @@ LINK_VERSION_TAG LINK_WIRELESS_VERSION = "vLinkWireless/v8.0.0";
#else
#define LINK_WIRELESS_TIMER_ISR
#endif
#define LINK_WIRELESS_ISR_FUNC(name, params, args, body) \
void name params; \
LINK_INLINE void _##name params body
#else
#define LINK_WIRELESS_SERIAL_ISR
#define LINK_WIRELESS_TIMER_ISR
#define LINK_WIRELESS_ISR_FUNC(name, params, args, body) \
void name params { \
_##name args; \
} \
LINK_INLINE void _##name params body
#endif
// ---
/**
* @brief A high level driver for the GBA Wireless Adapter.
@ -886,64 +896,44 @@ class LinkWireless {
#endif
}
#if defined(LINK_WIRELESS_PUT_ISR_IN_IWRAM) || \
defined(LINK_WIRELESS_ENABLE_NESTED_IRQ)
void _onSerial();
void _onTimer();
#else
void _onSerial() { __onSerial(); }
void _onTimer() { __onTimer(); }
#endif
/**
* @brief This method is called by the SERIAL interrupt handler.
* \warning This is internal API!
*/
LINK_INLINE void __onSerial() {
if (!isEnabled)
return;
#ifdef LINK_WIRELESS_PROFILING_ENABLED
profileStart();
LINK_WIRELESS_ISR_FUNC(_onSerial, (), (), {
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
interrupt = true;
LINK_BARRIER;
// (nested interrupts are enabled by LinkRawWireless::_onSerial(...))
#endif
int status = linkRawWireless._onSerial(false);
if (status <= -4) {
return (void)abort(Error::ACKNOWLEDGE_FAILED);
} else if (status > 0) {
auto result = linkRawWireless._getAsyncCommandResultRef();
processAsyncCommand(result);
}
___onSerial();
#ifdef LINK_WIRELESS_PROFILING_ENABLED
serialTime += profileStop();
serialIRQs++;
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
irqEnd();
#endif
}
})
/**
* @brief This method is called by the TIMER interrupt handler.
* \warning This is internal API!
*/
LINK_INLINE void __onTimer() {
if (!isEnabled)
LINK_WIRELESS_ISR_FUNC(_onTimer, (), (), {
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
if (interrupt)
return;
#ifdef LINK_WIRELESS_PROFILING_ENABLED
profileStart();
interrupt = true;
LINK_BARRIER;
Link::_REG_IME = 1;
#endif
if (!isSessionActive())
return;
___onTimer();
if (!isAsyncCommandActive())
checkConnectionsOrTransferData();
#ifdef LINK_WIRELESS_PROFILING_ENABLED
timerTime += profileStop();
timerIRQs++;
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
irqEnd();
#endif
}
})
struct Config {
bool forwarding;
@ -1086,10 +1076,8 @@ class LinkWireless {
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
volatile bool interrupt = false, pendingVBlank = false;
#endif
#ifdef LINK_WIRELESS_ENABLE_NESTED_IRQ
void irqEnd() {
LINK_INLINE void irqEnd() {
Link::_REG_IME = 0;
interrupt = false;
LINK_BARRIER;
@ -1100,6 +1088,48 @@ class LinkWireless {
}
#endif
LINK_INLINE void ___onSerial() {
if (!isEnabled)
return;
#ifdef LINK_WIRELESS_PROFILING_ENABLED
profileStart();
#endif
int status = linkRawWireless._onSerial(false);
if (status <= -4) {
return (void)abort(Error::ACKNOWLEDGE_FAILED);
} else if (status > 0) {
auto result = linkRawWireless._getAsyncCommandResultRef();
processAsyncCommand(result);
}
#ifdef LINK_WIRELESS_PROFILING_ENABLED
serialTime += profileStop();
serialIRQs++;
#endif
}
LINK_INLINE void ___onTimer() {
if (!isEnabled)
return;
#ifdef LINK_WIRELESS_PROFILING_ENABLED
profileStart();
#endif
if (!isSessionActive())
return;
if (!isAsyncCommandActive())
checkConnectionsOrTransferData();
#ifdef LINK_WIRELESS_PROFILING_ENABLED
timerTime += profileStop();
timerIRQs++;
#endif
}
LINK_INLINE void processAsyncCommand(
const LinkRawWireless::CommandResult* commandResult) { // (irq only)
if (!commandResult->success) {
@ -1164,7 +1194,7 @@ class LinkWireless {
}
}
LINK_WIRELESS_TIMER_ISR void checkConnectionsOrTransferData() { // (irq only)
void checkConnectionsOrTransferData() { // (irq only)
if (linkRawWireless.getState() == State::SERVING &&
!sessionState.signalLevelCalled) {
// SignalLevel (start)
@ -1185,7 +1215,7 @@ class LinkWireless {
}
}
LINK_WIRELESS_TIMER_ISR void sendPendingData() { // (irq only)
void sendPendingData() { // (irq only)
copyOutgoingState();
setDataFromOutgoingMessages();
@ -1193,9 +1223,9 @@ class LinkWireless {
clearInflightMessagesIfNeeded();
}
LINK_WIRELESS_TIMER_ISR void setDataFromOutgoingMessages() { // (irq only)
addAsyncData(0, true); // SendData header (filled later)
addAsyncData(0); // Transfer header (filled later)
void setDataFromOutgoingMessages() { // (irq only)
addAsyncData(0, true); // SendData header (filled later)
addAsyncData(0); // Transfer header (filled later)
bool isServer = linkRawWireless.getState() == State::SERVING;
u32 maxPacketIds = isServer ? MAX_PACKET_IDS_SERVER : MAX_PACKET_IDS_CLIENT;
@ -1285,12 +1315,11 @@ class LinkWireless {
nextAsyncCommandData[0] = linkRawWireless.getSendDataHeaderFor(bytes);
}
LINK_WIRELESS_TIMER_ISR u32
buildTransferHeader(bool isServer,
u32 firstPacketId,
u32 firstMsg,
u32 msgCount,
bool highPart) { // (irq only)
u32 buildTransferHeader(bool isServer,
u32 firstPacketId,
u32 firstMsg,
u32 msgCount,
bool highPart) { // (irq only)
TransferHeader transferHeader = {};
// player count / client heartbeat
@ -1335,7 +1364,7 @@ class LinkWireless {
return packer.asInt;
}
LINK_WIRELESS_TIMER_ISR void clearInflightMessagesIfNeeded() { // (irq only)
void clearInflightMessagesIfNeeded() { // (irq only)
if (config.retransmission)
return;
@ -1475,71 +1504,77 @@ class LinkWireless {
copyIncomingState();
}
LINK_WIRELESS_SERIAL_ISR void processMessage(
u32 playerId,
u32 data,
u32& currentPacketId,
u32& playerBitMap,
int& playerBitMapCount) { // (irq only)
// store the packet ID and increment (msgs are consecutive inside transfers)
u32 packetId = currentPacketId;
currentPacketId =
(currentPacketId + 1) %
(playerId == 0 ? MAX_PACKET_IDS_SERVER : MAX_PACKET_IDS_CLIENT);
LINK_WIRELESS_ISR_FUNC(
processMessage,
(u32 playerId,
u32 data,
u32& currentPacketId,
u32& playerBitMap,
int& playerBitMapCount),
(playerId, data, currentPacketId, playerBitMap, playerBitMapCount),
{
// (irq only)
// store the packet ID and increment (msgs are consecutive inside
// transfers)
u32 packetId = currentPacketId;
currentPacketId =
(currentPacketId + 1) %
(playerId == 0 ? MAX_PACKET_IDS_SERVER : MAX_PACKET_IDS_CLIENT);
// get msg player ID based on player bitmap
u32 msgPlayerId = playerId;
if (playerBitMapCount >= 0) {
msgPlayerId =
(playerBitMap >> PLAYER_ID_BITS * playerBitMapCount) & PLAYER_ID_MASK;
playerBitMapCount++;
// get msg player ID based on player bitmap
u32 msgPlayerId = playerId;
if (playerBitMapCount >= 0) {
msgPlayerId = (playerBitMap >> PLAYER_ID_BITS * playerBitMapCount) &
PLAYER_ID_MASK;
playerBitMapCount++;
if (playerBitMapCount >= MAX_PLAYER_BITMAP_ENTRIES &&
!((playerBitMap >> BIT_HAS_MORE) & 1))
playerBitMapCount = -1;
}
if (playerBitMapCount >= MAX_PLAYER_BITMAP_ENTRIES &&
!((playerBitMap >> BIT_HAS_MORE) & 1))
playerBitMapCount = -1;
}
if (playerId == 0 && !sessionState.didReceiveFirstPacketFromServer) {
// the first time clients receive something from the server,
// they shouldn't have any expectations (since they can join at any time)
sessionState.lastPacketIdFromServer = packetId;
sessionState.didReceiveFirstPacketFromServer = true;
} else {
// if retransmission is enabled, the packet ID needs to be expected
if (config.retransmission) {
u32 expectedPacketId =
playerId > 0
? (sessionState.lastPacketIdFromClients[playerId] + 1) %
MAX_PACKET_IDS_CLIENT
: (sessionState.lastPacketIdFromServer + 1) %
MAX_PACKET_IDS_SERVER;
if (playerId == 0 && !sessionState.didReceiveFirstPacketFromServer) {
// the first time clients receive something from the server,
// they shouldn't have any expectations (since they can join at any
// time)
sessionState.lastPacketIdFromServer = packetId;
sessionState.didReceiveFirstPacketFromServer = true;
} else {
// if retransmission is enabled, the packet ID needs to be expected
if (config.retransmission) {
u32 expectedPacketId =
playerId > 0
? (sessionState.lastPacketIdFromClients[playerId] + 1) %
MAX_PACKET_IDS_CLIENT
: (sessionState.lastPacketIdFromServer + 1) %
MAX_PACKET_IDS_SERVER;
if (packetId != expectedPacketId)
if (packetId != expectedPacketId)
return;
if (playerId > 0)
sessionState.lastPacketIdFromClients[playerId] = expectedPacketId;
else
sessionState.lastPacketIdFromServer = expectedPacketId;
}
}
// ignore messages from myself
if (msgPlayerId == linkRawWireless.sessionState.currentPlayerId)
return;
if (playerId > 0)
sessionState.lastPacketIdFromClients[playerId] = expectedPacketId;
else
sessionState.lastPacketIdFromServer = expectedPacketId;
}
}
// add new message
Message message;
message.playerId = msgPlayerId;
message.data = data;
message.packetId = packetId;
sessionState.newIncomingMessages.push(message);
// ignore messages from myself
if (msgPlayerId == linkRawWireless.sessionState.currentPlayerId)
return;
// add new message
Message message;
message.playerId = msgPlayerId;
message.data = data;
message.packetId = packetId;
sessionState.newIncomingMessages.push(message);
// forward to other clients if needed
if (playerId > 0 && config.forwarding &&
linkRawWireless.sessionState.playerCount > 2)
forwardMessage(message);
}
// forward to other clients if needed
if (playerId > 0 && config.forwarding &&
linkRawWireless.sessionState.playerCount > 2)
forwardMessage(message);
})
LINK_WIRELESS_SERIAL_ISR void forwardMessage(
Message& message) { // (irq only)
@ -1661,22 +1696,24 @@ class LinkWireless {
return true;
}
LINK_INLINE u32 newPacketId(u32 maxPacketIds) { // (irq only)
LINK_WIRELESS_TIMER_ISR u32 newPacketId(u32 maxPacketIds) { // (irq only)
return (sessionState.lastPacketId =
(sessionState.lastPacketId + 1) % maxPacketIds);
}
LINK_INLINE void addToLastAsyncDataHalfword(u16 value) { // (irq only)
LINK_WIRELESS_TIMER_ISR void addToLastAsyncDataHalfword(
u16 value) { // (irq only)
addToAsyncDataShifted(nextAsyncCommandDataSize - 1, value, 16);
}
LINK_INLINE void addToAsyncDataShifted(u32 index,
u16 value,
u32 shift) { // (irq only)
LINK_WIRELESS_TIMER_ISR void addToAsyncDataShifted(u32 index,
u16 value,
u32 shift) { // (irq only)
nextAsyncCommandData[index] |= value << shift;
}
LINK_INLINE void addAsyncData(u32 value, bool start = false) { // (irq only)
LINK_WIRELESS_TIMER_ISR void addAsyncData(u32 value,
bool start = false) { // (irq only)
if (start)
nextAsyncCommandDataSize = 0;
nextAsyncCommandData[nextAsyncCommandDataSize] = value;