From 607eec3c1ff2bd15a407eeeaeab9f93ed7ab0e8d Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Tue, 7 Feb 2023 17:55:49 -0300 Subject: [PATCH] Trying to fix LinkCable random crash --- examples/LinkCable_full/src/main.cpp | 4 +- lib/LinkCable.h | 55 +++++++++++++++++++++------- lib/LinkUniversal.h | 35 +++--------------- 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/examples/LinkCable_full/src/main.cpp b/examples/LinkCable_full/src/main.cpp index 635e24e..bc14c92 100644 --- a/examples/LinkCable_full/src/main.cpp +++ b/examples/LinkCable_full/src/main.cpp @@ -78,8 +78,8 @@ void printTutorial() { DEBULOG("START: turn on connection"); DEBULOG("(on connection, p1 sends 999)"); DEBULOG(""); - DEBULOG("A: send counter++ (once)"); - DEBULOG("B: send counter++ (cont)"); + DEBULOG("B: send counter++ (once)"); + DEBULOG("A: send counter++ (cont)"); DEBULOG("L: send counter++ twice (once)"); DEBULOG("R: send counter++ twice (cont)"); DEBULOG("SELECT: force lag (9k lines)"); diff --git a/lib/LinkCable.h b/lib/LinkCable.h index f74c03e..f1d03e0 100644 --- a/lib/LinkCable.h +++ b/lib/LinkCable.h @@ -60,6 +60,7 @@ #define LINK_CABLE_BIT_GENERAL_PURPOSE_HIGH 15 #define LINK_CABLE_SET_HIGH(REG, BIT) REG |= 1 << BIT #define LINK_CABLE_SET_LOW(REG, BIT) REG &= ~(1 << BIT) +#define LINK_CABLE_BARRIER asm volatile("" ::: "memory") static volatile char LINK_CABLE_VERSION[] = "LinkCable/v4.3.0"; @@ -77,8 +78,6 @@ class LinkCable { std::queue incomingMessages[LINK_CABLE_MAX_PLAYERS]; u8 playerCount; u8 currentPlayerId; - bool isReady = false; - bool isConsumed = false; }; struct InternalState { @@ -86,7 +85,6 @@ class LinkCable { int timeouts[LINK_CABLE_MAX_PLAYERS]; bool IRQFlag; u32 IRQTimeout; - bool isAddingMessage = false; }; enum BaudRate { @@ -119,6 +117,9 @@ class LinkCable { void deactivate() { isEnabled = false; + isStateReady = false; + isStateConsumed = false; + isResetting = false; resetState(); stop(); } @@ -132,28 +133,43 @@ class LinkCable { u8 currentPlayerId() { return $state.currentPlayerId; } bool canRead(u8 playerId) { - if (!$state.isReady) + if (!isStateReady || isStateConsumed) return false; + LINK_CABLE_BARRIER; + return !$state.incomingMessages[playerId].empty(); } u16 read(u8 playerId) { - if (!$state.isReady) + if (!isStateReady || isStateConsumed) return LINK_CABLE_NO_DATA; + LINK_CABLE_BARRIER; + return LINK_CABLE_QUEUE_POP($state.incomingMessages[playerId]); } - void consume() { $state.isConsumed = true; } + void consume() { isStateConsumed = true; } void send(u16 data) { if (data == LINK_CABLE_DISCONNECTED || data == LINK_CABLE_NO_DATA) return; - _state.isAddingMessage = true; + LINK_CABLE_BARRIER; + isAddingMessage = true; + LINK_CABLE_BARRIER; + push(_state.outgoingMessages, data); - _state.isAddingMessage = false; + + LINK_CABLE_BARRIER; + isAddingMessage = false; + LINK_CABLE_BARRIER; + + if (isResetting) { + LINK_CABLE_QUEUE_CLEAR(_state.outgoingMessages); + isResetting = false; + } } void _onVBlank() { @@ -238,6 +254,10 @@ class LinkCable { u32 interval; u8 sendTimerId; bool isEnabled = false; + bool isStateReady = false; + bool isStateConsumed = false; + bool isAddingMessage = false; + bool isResetting = false; bool isReady() { return isBitHigh(LINK_CABLE_BIT_READY); } bool hasError() { return isBitHigh(LINK_CABLE_BIT_ERROR); } @@ -246,9 +266,11 @@ class LinkCable { bool didTimeout() { return _state.IRQTimeout >= timeout; } void sendPendingData() { - if (_state.isAddingMessage) + if (isAddingMessage) return; + LINK_CABLE_BARRIER; + transfer(LINK_CABLE_QUEUE_POP(_state.outgoingMessages)); } @@ -281,9 +303,13 @@ class LinkCable { LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]); _state.timeouts[i] = LINK_CABLE_REMOTE_TIMEOUT_OFFLINE; } - LINK_CABLE_QUEUE_CLEAR(_state.outgoingMessages); _state.IRQFlag = false; _state.IRQTimeout = 0; + + if (isAddingMessage || isResetting) + isResetting = true; + else + LINK_CABLE_QUEUE_CLEAR(_state.outgoingMessages); } void stop() { @@ -313,12 +339,15 @@ class LinkCable { } void copyState() { - if ($state.isReady && !$state.isConsumed) + if (isStateReady && !isStateConsumed) return; - state.isReady = true; - state.isConsumed = false; + LINK_CABLE_BARRIER; $state = state; + LINK_CABLE_BARRIER; + isStateReady = true; + isStateConsumed = false; + LINK_CABLE_BARRIER; for (u32 i = 0; i < LINK_CABLE_MAX_PLAYERS; i++) LINK_CABLE_QUEUE_CLEAR(state.incomingMessages[i]); diff --git a/lib/LinkUniversal.h b/lib/LinkUniversal.h index 694ef5c..edc5a07 100644 --- a/lib/LinkUniversal.h +++ b/lib/LinkUniversal.h @@ -48,7 +48,7 @@ #define LINK_UNIVERSAL_WIRELESS_TX_PER_FRAME 5 #define LINK_UNIVERSAL_MAX_ROOM_NUMBER 32000 #define LINK_UNIVERSAL_INIT_WAIT_FRAMES 10 -#define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES 20 +#define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES 25 #define LINK_UNIVERSAL_SWITCH_WAIT_FRAMES_RANDOM 10 #define LINK_UNIVERSAL_BROADCAST_SEARCH_WAIT_FRAMES 10 #define LINK_UNIVERSAL_SERVE_WAIT_FRAMES 30 @@ -202,29 +202,9 @@ class LinkUniversal { u32 getWaitCount() { return waitCount; } u32 getSubWaitCount() { return subWaitCount; } - void _onVBlank() { - if (!isEnabled) - return; - - if (mode == LINK_CABLE) - linkCable->_onVBlank(); - } - - void _onTimer() { - if (!isEnabled) - return; - - if (mode == LINK_CABLE) - linkCable->_onTimer(); - } - - void _onSerial() { - if (!isEnabled) - return; - - if (mode == LINK_CABLE) - linkCable->_onSerial(); - } + void _onVBlank() { linkCable->_onVBlank(); } + void _onTimer() { linkCable->_onTimer(); } + void _onSerial() { linkCable->_onSerial(); } ~LinkUniversal() { delete linkCable; @@ -247,11 +227,8 @@ class LinkUniversal { void receiveCableMessages() { for (u32 i = 0; i < LINK_UNIVERSAL_MAX_PLAYERS; i++) { - // TODO: FIX CRASH - // TODO: RETRIEVE ALL MESSAGES - if (linkCable->canRead(i)) - linkCable->read(i); - // push(incomingMessages[i], qran_range(1, 10000)); + while (linkCable->canRead(i)) + push(incomingMessages[i], linkCable->read(i)); } }