From b272ebafdbf0072377f01df234aa2de7a3380794 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Fri, 16 Aug 2024 00:45:10 -0300 Subject: [PATCH] Adding gracefully shutdown method --- examples/LinkMobile_demo/src/main.cpp | 51 +++++++++----- lib/LinkMobile.hpp | 96 +++++++++++++++++++++------ 2 files changed, 109 insertions(+), 38 deletions(-) diff --git a/examples/LinkMobile_demo/src/main.cpp b/examples/LinkMobile_demo/src/main.cpp index 3d907dd..ed5b82a 100644 --- a/examples/LinkMobile_demo/src/main.cpp +++ b/examples/LinkMobile_demo/src/main.cpp @@ -60,7 +60,7 @@ start: // Menu std::string output = ""; - bool wait = false; + bool shouldHang = false; output += "State = " + getStateString(linkMobile->getState()) + "\n\n"; auto error = linkMobile->getError(); @@ -76,36 +76,47 @@ start: " CmdErrorCode: " + std::to_string(error.cmdErrorCode) + "\n\n"; output += " (SELECT = stop)"; - } else if (linkMobile->getState() == LinkMobile::SESSION_ACTIVE) { + } else if (linkMobile->isSessionActive()) { output += "L = Read Configuration\n\n"; output += " (DOWN = ok)\n (SELECT = stop)"; } else { output += " (SELECT = stop)"; } - // SELECT = back + // SELECT = stop if (keys & KEY_SELECT) { - linkMobile->deactivate(); - interrupt_disable(INTR_VBLANK); - interrupt_disable(INTR_SERIAL); - interrupt_disable(INTR_TIMER3); - delete linkMobile; - linkMobile = NULL; - goto start; + bool didShutdown = linkMobile->getState() == LinkMobile::State::SHUTDOWN; + if (hasError || didShutdown) { + linkMobile->deactivate(); + interrupt_disable(INTR_VBLANK); + interrupt_disable(INTR_SERIAL); + interrupt_disable(INTR_TIMER3); + delete linkMobile; + linkMobile = NULL; + + if (!didShutdown) { + log("Waiting..."); + wait(228 * 60 * 3); + } + + goto start; + } else if (linkMobile->isSessionActive()) { + linkMobile->shutdown(); + } } // L = Read Configuration if ((keys & KEY_L) && !reading) { reading = true; output = readConfiguration(); - wait = true; + shouldHang = true; } if (reading && !(keys & KEY_L)) reading = false; VBlankIntrWait(); log(output); - if (wait) + if (shouldHang) hang(); } @@ -155,18 +166,26 @@ std::string getStateString(LinkMobile::State state) { return "PINGING"; case LinkMobile::State::WAITING_TO_START: return "WAITING_TO_START"; - case LinkMobile::State::ENDING_SESSION: - return "ENDING_SESSION"; case LinkMobile::State::STARTING_SESSION: return "STARTING_SESSION"; case LinkMobile::State::ACTIVATING_SIO32: return "ACTIVATING_SIO32"; - case LinkMobile::State::WAITING_TO_SWITCH: - return "WAITING_TO_SWITCH"; + case LinkMobile::State::WAITING_32BIT_SWITCH: + return "WAITING_32BIT_SWITCH"; case LinkMobile::State::READING_CONFIGURATION: return "READING_CONFIGURATION"; case LinkMobile::State::SESSION_ACTIVE: return "SESSION_ACTIVE"; + case LinkMobile::State::SHUTDOWN_REQUESTED: + return "SHUTDOWN_REQUESTED"; + case LinkMobile::State::DEACTIVATING_SIO32: + return "DEACTIVATING_SIO32"; + case LinkMobile::State::WAITING_8BIT_SWITCH: + return "WAITING_8BIT_SWITCH"; + case LinkMobile::State::ENDING_SESSION: + return "ENDING_SESSION"; + case LinkMobile::State::SHUTDOWN: + return "SHUTDOWN"; default: return "???"; } diff --git a/lib/LinkMobile.hpp b/lib/LinkMobile.hpp index 2bcee6f..d81dba5 100644 --- a/lib/LinkMobile.hpp +++ b/lib/LinkMobile.hpp @@ -95,14 +95,18 @@ class LinkMobile { NEEDS_RESET, PINGING, WAITING_TO_START, - ENDING_SESSION, STARTING_SESSION, ACTIVATING_SIO32, - WAITING_TO_SWITCH, + WAITING_32BIT_SWITCH, READING_CONFIGURATION, SESSION_ACTIVE, SESSION_ACTIVE_CALL, - SESSION_ACTIVE_ISP + SESSION_ACTIVE_ISP, + SHUTDOWN_REQUESTED, + DEACTIVATING_SIO32, + WAITING_8BIT_SWITCH, + ENDING_SESSION, + SHUTDOWN }; enum CommandResult { @@ -182,6 +186,15 @@ class LinkMobile { start(); } + bool shutdown() { + if (!isSessionActive()) + return false; + + error = {}; + setState(SHUTDOWN_REQUESTED); + return true; + } + void deactivate() { error = {}; isEnabled = false; @@ -190,7 +203,7 @@ class LinkMobile { } bool readConfiguration(ConfigurationData& configurationData) { - if (state != SESSION_ACTIVE) + if (!isSessionActive()) return false; configurationData = adapterConfiguration.fields; @@ -199,6 +212,13 @@ class LinkMobile { [[nodiscard]] State getState() { return state; } + /** + * @brief Returns `true` if the session is active. + */ + [[nodiscard]] bool isSessionActive() { + return state >= SESSION_ACTIVE && state < SHUTDOWN_REQUESTED; + } + [[nodiscard]] LinkSPI::DataSize getDataSize() { return linkSPI->getDataSize(); } @@ -249,6 +269,8 @@ class LinkMobile { } else { processLoosePacket(newData); } + + _LMLOG_("<<<< %X", newData); } void _onTimer() { @@ -399,12 +421,12 @@ class LinkMobile { waitFrames--; if (waitFrames == 0) { - setState(ENDING_SESSION); - cmdEndSession(); + setState(STARTING_SESSION); + cmdBeginSession(); } break; } - case WAITING_TO_SWITCH: { + case WAITING_32BIT_SWITCH: { waitFrames--; if (waitFrames == 0) { @@ -415,6 +437,24 @@ class LinkMobile { } break; } + case SHUTDOWN_REQUESTED: { + if (!asyncCommand.isActive) { + setState(DEACTIVATING_SIO32); + cmdSIO32(false); + } + break; + } + case WAITING_8BIT_SWITCH: { + waitFrames--; + + if (waitFrames == 0) { + linkSPI->activate(LinkSPI::Mode::MASTER_256KBPS, + LinkSPI::DataSize::SIZE_8BIT); + setState(ENDING_SESSION); + cmdEndSession(); + } + break; + } default: { } } @@ -444,14 +484,6 @@ class LinkMobile { } switch (state) { - case ENDING_SESSION: { - if (!asyncCommand.respondsTo(COMMAND_END_SESSION)) - return; - - setState(STARTING_SESSION); - cmdBeginSession(); - break; - } case STARTING_SESSION: { if (!asyncCommand.respondsTo(COMMAND_BEGIN_SESSION)) return; @@ -464,7 +496,7 @@ class LinkMobile { } setState(ACTIVATING_SIO32); - cmdSIO32(); + cmdSIO32(true); break; } case ACTIVATING_SIO32: { @@ -479,7 +511,7 @@ class LinkMobile { if (!asyncCommand.respondsTo(COMMAND_SIO32)) return; - setState(WAITING_TO_SWITCH); + setState(WAITING_32BIT_SWITCH); waitFrames = PING_WAIT_FRAMES; break; } @@ -509,6 +541,22 @@ class LinkMobile { setState(SESSION_ACTIVE); break; } + case DEACTIVATING_SIO32: { + if (!asyncCommand.respondsTo(COMMAND_SIO32) && + !asyncCommand.respondsTo(COMMAND_RESET)) + return abort(Error::Type::WEIRD_RESPONSE); + + setState(WAITING_8BIT_SWITCH); + waitFrames = PING_WAIT_FRAMES; + break; + } + case ENDING_SESSION: { + if (!asyncCommand.respondsTo(COMMAND_END_SESSION)) + return; + + setState(SHUTDOWN); + break; + } default: { } } @@ -536,8 +584,8 @@ class LinkMobile { sendCommandAsync(buildCommand(COMMAND_END_SESSION), true); } - void cmdSIO32() { - addData(1, true); + void cmdSIO32(bool enabled) { + addData(enabled, true); sendCommandAsync(buildCommand(COMMAND_SIO32, true), true); } @@ -568,7 +616,7 @@ class LinkMobile { State oldState = state; state = newState; timeoutFrames = 0; - _LMLOG_("!! New state: %d -> %d", oldState, newState); + _LMLOG_("!! new state: %d -> %d", oldState, newState); (void)oldState; } @@ -673,7 +721,7 @@ class LinkMobile { bool isAcknowledgement = asyncCommand.transferred >= mainSize + CHECKSUM_SIZE + 1; if (!isAcknowledgement && newData != ADAPTER_WAITING) { - _LMLOG_("NOT WAITING: %X", newData); // TODO: REMOVE + _LMLOG_("!! not waiting: %X", newData); return asyncCommand.fail(CommandResult::NOT_WAITING); } @@ -708,8 +756,10 @@ class LinkMobile { bool isAcknowledgement = asyncCommand.transferred >= mainSize + 4; if (!isAcknowledgement && newData != ADAPTER_WAITING && - newData != ADAPTER_WAITING_32BIT) + newData != ADAPTER_WAITING_32BIT) { + _LMLOG_("!! not waiting: %X", newData); return asyncCommand.fail(CommandResult::NOT_WAITING); + } if (asyncCommand.transferred == 4) { // Header+Data || Header+Checksum @@ -917,6 +967,8 @@ class LinkMobile { } void transferAsync(u32 data) { + _LMLOG_(">>>> %X", data); + hasPendingTransfer = true; pendingTransfer = data; startTimer(WAIT_TICKS[isSIO32Mode()]);