 // which may mean deferring work at certain times
 // such as the end of minor cycle.
 // The Print object pointer must not be NULL.
-bool handleQueuedMessages(Print *p, bool wakeSerialIfNeeded, OTRadioLink::OTRadioLink *rl)
-  {
-  // Avoid starting any potentially-slow processing very late in the minor cycle.
-  // This is to reduce the risk of loop overruns
-  // at the risk of delaying some processing
-  // or even dropping some incoming messages if queues fill up.
-  // Decoding (and printing to serial) a secure 'O' frame takes ~60 ticks (~0.47s).
-  // Allow for up to 0.5s of such processing worst-case,
-  // ie don't start processing anything later that 0.5s before the minor cycle end.
-  const uint8_t sctStart = OTV0P2BASE::getSubCycleTime();
-  if(sctStart >= ((OTV0P2BASE::GSCT_MAX/4)*3)) { return(false); }
-
-  // Deal with any I/O that is queued.
+static bool handleQueuedMessages(Print *p, OTRadioLink::OTRadioLink *rl)
+{
+    // Avoid starting any potentially-slow processing very late in the minor cycle.
+    // This is to reduce the risk of loop overruns
+    // at the risk of delaying some processing
+    // or even dropping some incoming messages if queues fill up.
+    // Decoding (and printing to serial) a secure 'O' frame takes ~60 ticks (~0.47s).
+    // Allow for up to 0.5s of such processing worst-case,
+    // ie don't start processing anything later that 0.5s before the minor cycle end.
+    const uint8_t sctStart = OTV0P2BASE::getSubCycleTime();
+    if(sctStart >= ((OTV0P2BASE::GSCT_MAX/4)*3)) { return(false); }
+  
+    // Deal with any I/O that is queued.
     // Poll for inbound frames.
     // If RX is not interrupt-driven then
     // there will usually be little time to do this
     // before getting an RX overrun or dropped frame.
     PrimaryRadio.poll();
     SecondaryRadio.poll();
-
-  // XXX can probably strip these out.
-  bool workDone = false;
-  bool neededWaking = false; // Set true once this routine wakes Serial.
-  const volatile uint8_t *pb;
-  if(NULL != (pb = rl->peekRXMsg()))
-    {
-    if(wakeSerialIfNeeded && OTV0P2BASE::powerUpSerialIfDisabled<V0P2_UART_BAUD>()) { neededWaking = true; } // FIXME
-    // Don't currently regard anything arriving over the air as 'secure'.
-    // FIXME: shouldn't have to cast away volatile to process the message content.
-    decodeAndHandleOTSecureableFrame(p, (const uint8_t *)pb);
-    rl->removeRXMsg();
-    // Note that some work has been done.
-    workDone = true;
-    }
-
-  // Turn off serial at end, if this routine woke it.
-  if(neededWaking) { OTV0P2BASE::flushSerialProductive(); OTV0P2BASE::powerDownSerial(); } // XXX move into if clause
-  return(workDone);
-  }
+  
+    const volatile uint8_t *pb; // XXX
+    if(NULL != (pb = rl->peekRXMsg())) {
+        bool neededWaking = false; // Set true once this routine wakes Serial.
+        if(OTV0P2BASE::powerUpSerialIfDisabled<V0P2_UART_BAUD>()) { neededWaking = true; } // FIXME
+        // Don't currently regard anything arriving over the air as 'secure'.
+        // FIXME: shouldn't have to cast away volatile to process the message content.
+        decodeAndHandleOTSecureableFrame((const uint8_t *)pb);
+        rl->removeRXMsg();
+        // Turn off serial at end, if this routine woke it.
+        if(neededWaking) { OTV0P2BASE::flushSerialProductive(); OTV0P2BASE::powerDownSerial(); } // XXX move into if clause
+        // Note that some work has been done.
+        return (true);
+    }
+    return(false);
+}
 
 //========================================
 // INTERRUPT SERVICE ROUTINES
 //========================================
-  //// Interrupt count.  Marked volatile so safe to read without a lock as is a single byte.
-//static volatile uint8_t intCountPB;
 // Previous state of port B pins to help detect changes.
 static volatile uint8_t prevStatePB;
 // Interrupt service routine for PB I/O port transition changes.
 ISR(PCINT0_vect)
   {
-//  ++intCountPB;
   const uint8_t pins = PINB;
   const uint8_t changes = pins ^ prevStatePB;
   prevStatePB = pins;
   // RFM23B nIRQ falling edge is of interest.
   // Handler routine not required/expected to 'clear' this interrupt.
   // TODO: try to ensure that OTRFM23BLink.handleInterruptSimple() is inlineable to minimise ISR prologue/epilogue time and space.
-  if((changes & RFM23B_INT_MASK) && !(pins & RFM23B_INT_MASK))
-    { PrimaryRadio.handleInterruptSimple(); }
+  if((changes & RFM23B_INT_MASK) && !(pins & RFM23B_INT_MASK)) { PrimaryRadio.handleInterruptSimple(); }
   }
 
 


// Assign radio to SecondaryRadio alias.
OTRadioLink::OTRadioLink &SecondaryRadio = SIM900;

//////// Constants and variables
// Controller's view of Least Significant Digits of the current (local) time, in this case whole seconds.

// Main loop for OpenTRV radiator control.
// Note: exiting and re-entering can take a little while, handling Arduino background tasks such as serial.
void loop()
{
    // CHECK STACK
    // ===============
    // Force restart if SPAM/heap/stack likely corrupt.
    OTV0P2BASE::MemoryChecks::forceResetIfStackOverflow();
    // 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();
    if(minsp < 64) { OTV0P2BASE::serialPrintlnAndFlush(F("!SH")); }
  
    // SLEEP
    // ===============
    // Sleep in low-power mode (waiting for interrupts) until seconds roll.
    // NOTE: sleep at the top of the loop to minimise timing jitter/delay from Arduino background activity after loop() returns.
    // DHD20130425: waking up from sleep and getting to start processing below this block may take >10ms.
    // Ensure that serial I/O is off while sleeping.
    OTV0P2BASE::powerDownSerial();
    // Power down most stuff (except radio for hub RX).
    OTV0P2BASE::minimisePowerWithoutSleep();
    uint_fast8_t newTLSD;
    while(TIME_LSD == (newTLSD = OTV0P2BASE::getSecondsLT())) {
        // Poll I/O and process message incrementally (in this otherwise idle time)
        // before sleep and on wakeup in case some IO needs further processing now,
        // eg work was accrued during the previous major slow/outer loop
        // or the in a previous orbit of this loop sleep or nap was terminated by an I/O interrupt.
        // May generate output to host on Serial.
        // Come back and have another go immediately until no work remaining.
        if(handleQueuedMessages(&Serial, &PrimaryRadio)) { continue; }
    
        // Normal long minimal-power sleep until wake-up interrupt.
        // Rely on interrupt to force quick loop round to I/O poll.
        OTV0P2BASE::sleepUntilInt();
    }
    TIME_LSD = newTLSD;
    // Reset and immediately re-prime the RTC-based watchdog.
    OTV0P2BASE::resetRTCWatchDog();
    OTV0P2BASE::enableRTCWatchdog(true);
  
  
    // START LOOP BODY
    // ===============  
    // Handling the UI may have taken a little while, so process I/O a little.
    handleQueuedMessages(&Serial, &PrimaryRadio); // Deal with any pending I/O.
    
    // High-priority UI handing, every other/even second.
    // Show status if the user changed something significant.
    // Must take ~300ms or less so as not to run over into next half second if two TXs are done.
    switch(TIME_LSD) { // With V0P2BASE_TWO_S_TICK_RTC_SUPPORT only even seconds are available.
        // Tasks that must be run every minute.
        // Note simple roll-over to 0 at max value.
        case 0: { ++minuteCount; break; }
        // Churn/reseed PRNG(s) a little to improve unpredictability in use: should be lightweight.
        case 2: { if(minuteCount & 3) { OTV0P2BASE::seedRNG8(minuteCount ^ OTV0P2BASE::getCPUCycleCount(), OTV0P2BASE::_getSubCycleTime(), 0xff); } break; }
    }
    
    // End-of-loop processing, that may be slow.
    // Ensure progress on queued messages ahead of slow work.  (TODO-867)
    handleQueuedMessages(&Serial, &PrimaryRadio); // Deal with any pending I/O.
}

