 //========================================
 // MAIN LOOP
 //========================================
-
-inline void stackCheck()
-{
-    // Force restart if SPAM/heap/stack likely corrupt.
-    // Complain and keep complaining when getting near stack overflow.
-    // TODO: make DEBUG-only when confident all configs OK.
-    const int16_t minsp = OTV0P2BASE::MemoryChecks::getMinSPSpaceBelowStackToEnd();
-    const uint8_t location = OTV0P2BASE::MemoryChecks::getLocation();
-    OTV0P2BASE::serialPrintAndFlush(F("minsp: "));
-    OTV0P2BASE::serialPrintAndFlush(minsp);
-    OTV0P2BASE::serialPrintAndFlush(F(" loc:"));
-    OTV0P2BASE::serialPrintAndFlush(location);
-    OTV0P2BASE::serialPrintlnAndFlush();
-
-    OTV0P2BASE::MemoryChecks::forceResetIfStackOverflow();
-
-    OTV0P2BASE::MemoryChecks::resetMinSP();
-}
-
 void loop()
 {
     stackCheck();

  }


// Messaging
// Setup frame RX handlers
// Define queue handler
// Currently 4 possible cases for RXing secure frames:
// - Both relay and boiler hub present (e.g. CONFIG_REV10_AS_BHR)
// - Just relay present (e.g. CONFIG_REV10_AS_GSM_RELAY_ONLY)
// - Just boiler hub (e.g. CONFIG_REV8_SECURE_BHR)
// - Unit acting as stats-hub (e.g. CONFIG_REV11_SECURE_STATSHUB)
// relay + bh
constexpr size_t RX_WorkspaceSize = OTAESGCM::OTAES128GCMGenericWithWorkspace<>::workspaceRequiredDec + 16 + 58;
inline bool decodeAndHandleSecureFrame(volatile const uint8_t * const msg)
{
//    constexpr size_t workspaceSize = OTAESGCM::OTAES128GCMGenericWithWorkspace<>::workspaceRequiredDec + 74;
    uint8_t workspace[RX_WorkspaceSize];
    OTV0P2BASE::ScratchSpaceL sW(workspace, sizeof(workspace));
    // Temporarily suspend PrimaryRadio interrupts to avoid stack collisions.
    PrimaryRadio.pauseInterrupts(true);
    const bool success = OTRadioLink::decodeAndHandleOTSecureOFrameWithWorkspace<OTRadioLink::SimpleSecureFrame32or0BodyRXV0p2,
                                                    OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleDec_DEFAULT_WITH_LWORKSPACE,
                                                   OTV0P2BASE::getPrimaryBuilding16ByteSecretKey,
                                                   OTRadioLink::relayFrameOperation<decltype(SecondaryRadio), SecondaryRadio>,
                                                   OTRadioLink::boilerFrameOperation<decltype(BoilerHub), BoilerHub, minuteCount>
                                                  >(msg, sW);
    // Reenable interrupt line.
    PrimaryRadio.pauseInterrupts(false);
    return (success);
}
OTRadioLink::OTMessageQueueHandler< pollIO, V0P2_UART_BAUD,
                                    decodeAndHandleSecureFrame, OTRadioLink::decodeAndHandleDummyFrame
                                   > messageQueue;  //TODO change baud


//========================================

        ss1.enableCount(false);
        ss1.putOrRemove(OTV0P2BASE::ErrorReporter);
        ss1.put(TemperatureC16);

        // OPTIONAL items
        constexpr uint8_t privacyLevel = OTV0P2BASE::stTXalwaysAll;

        // Redirect JSON output appropriately.
        // |    0    |     1    | 2 |  3:n | n+1 | n+2 | n is the end of the stats message. n+2 <= 34
        // | valvePC | hasStats | { | json | '}' | 0x0 |
        // ptextBuf is the entire frame
        uint8_t *const ptextBuf = sW.buf + MSG_BUF_SIZE;
        // bufJSON is just the stats message part of the frame. (valvePC and hasStats are not part of this).
        uint8_t *const bufJSON = ptextBuf + 2;

        // Number of bytes written for body.
        // For non-secure, this is the size of the JSON text.
