Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Revision:
40:1324da35afd4
Parent:
39:2f17131d22a5
Child:
41:d6f5e2f09e07
--- a/main.cpp	Tue Jul 30 02:03:21 2013 +0000
+++ b/main.cpp	Sat Oct 05 04:45:22 2013 +0000
@@ -6,11 +6,11 @@
 #define DISABLE_CONFIG_SAFETYNETS
 
 #define ENABLE_AFAR_COMM
-#define ENABLE_SBD_COMM
+//#define ENABLE_SBD_COMM
 //#define ENABLE_USB_COMM
 //#define ENABLE_AFAR_TWITTER
 
-//#define USE_RTOS_TIMER
+//#define USE_RTOS // change in CommConstants and EthernetPower also
 //#define USE_ETH_INTERFACE
 //#define EVT_TIME_PROFILE
 //#define DEBUG
@@ -35,6 +35,7 @@
 #include "SnStatusFrame.h"
 #include "SnHeaderFrame.h"
 #include "SnHeartbeatFrame.h"
+#include "SnClockSetFrame.h"
 #include "SnCommWin.h"
 #ifdef USE_ETH_INTERFACE
 #include "SnCommAfarTCP.h"
@@ -55,6 +56,7 @@
 #include "RtosTimer.h"
 #endif
 
+extern "C" void mbed_reset();
 
 //
 // MBED PINS (ordered by number)
@@ -131,14 +133,15 @@
 void                      SaveEvent(const int32_t etms);
 void                      WaitTrigAndSendClock();
 void                      SetConfigAndMakeOutputFile();
-SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig=false);
+SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig=false,
+                                      const bool isStartupWin=false);
 void                      MakeOutputFile(const bool stopRunning=false);
 void                      SetPower(const bool isCommWin);
 void                      procForceTrigger();
 void                      procHeartbeat();
 void                      procPowerCheck();
 void                      procCommWin();
-#ifdef USE_RTOS_TIMER
+#ifdef USE_RTOS
 void                      procForceTrigger(void const *) { return procForceTrigger(); }
 void                      procHeartbeat(void const *) { return procHeartbeat(); }
 void                      procPowerCheck(void const *) { return procPowerCheck(); }
@@ -150,7 +153,7 @@
 //
 // readout objs
 // TODO: use RtosTimer instead of Ticker?
-#ifdef USE_RTOS_TIMER
+#ifdef USE_RTOS
 static rtos::RtosTimer*     gForceTicker;
 static rtos::RtosTimer*     gHeartbeatTicker;
 static rtos::RtosTimer*     gCommWinTicker;
@@ -161,14 +164,17 @@
 static Ticker         gCommWinTicker;
 static Ticker         gPowerCheckTicker;
 #endif
-static Timer          gTrgTimer;
+static Timer          gAllTrgTimer;
+static Timer          gThmTrgTimer;
 static Timer          gAdcToMBtimer;
+static SnClockSetFrame gClkSet;
 #ifdef DISABLE_CONFIG_SAFETYNETS
 static SnConfigFrame  gConf(false);
 #else
 static SnConfigFrame  gConf;
 #endif
 static SnEventFrame   gEvent;
+static SnEventFrame   gLastEvent;
 static SnPowerFrame   gPower;
 // parameters
 static bool           gCardsPowered     = false;
@@ -184,6 +190,7 @@
 static time_t         gLastCommWin      = 0; // time
 static uint32_t       gCommWinChecks    = 0;
 static uint32_t       gNcommWinChecks   = 0;
+static uint16_t       gConsecCommFails  = 0;
 // heartbeat
 static time_t         gLastHrtbt        = 0;
 static volatile bool  gHrtbtFired       = false;
@@ -194,7 +201,8 @@
 static uint32_t       gThmNumDt         = 0; // number of thermal trig time diffs added up
 static uint32_t       gEvtNumDt         = 0; // number of event time diffs added up
 // this should be bigger than anything that will actually be used
-static const uint32_t gBufSize=SnStatusFrame::kMaxSizeOf + (2u*SnHeaderFrame::kMaxSizeOf) + SnPowerFrame::kMaxSizeOf;
+static const uint32_t gBufSize=SnStatusFrame::kMaxSizeOf + (2u*SnHeaderFrame::kMaxSizeOf) + SnPowerFrame::kMaxSizeOf
+                                + SnEventFrame::kMaxSizeOf; // (this is redundant and could be removed if mem is sparse)
 //static const uint32_t gB64Bsize=BASE64ENC_LEN(gBufSize)+1;
 //static char           gB64Buf[gB64Bsize];
 static char           gGenBuf[gBufSize]; // must be big enough for event or status or config!
@@ -352,7 +360,7 @@
     const uint32_t evtStartCurSeq = (SnSDUtils::GetCurSeqNum()) // no -1; start with seq=0
                                      * gConf.GetEvtsPerFile();
     gEvent.ClearEvent();
-    gEvtNum = gConf.GetFirstEvt() + evtStartCurSeq;
+    gEvtNum = evtStartCurSeq;
     gPowNum = evtStartCurSeq;
     memset(gTrgNum, 0, sizeof(uint32_t)*kNumTrgs);
     // reset rate counters
@@ -402,9 +410,9 @@
 
 bool IsSeqComplete() {
 #ifdef DEBUG
-    printf("IsSeqComplete: eps=%u, cntpow=%d, fe=%u, pow=%u, evt=%u, seq=%hu\r\n",
+    printf("IsSeqComplete: eps=%u, cntpow=%d, pow=%u, evt=%u, seq=%hu\r\n",
         gConf.GetEvtsPerFile(), (int)gConf.IsCountingPowerReadings(),
-        gConf.GetFirstEvt(), gPowNum, gEvtNum, SnSDUtils::GetCurSeqNum());
+        gPowNum, gEvtNum, SnSDUtils::GetCurSeqNum());
 #endif
     if (gConf.GetEvtsPerFile()>0) {
         const uint32_t evtEndCurSeq = (SnSDUtils::GetCurSeqNum()+1) // account for seq=0
@@ -416,14 +424,14 @@
             return (gPowNum>=evtEndCurSeq);
         } else {
             // first event num is a one-time per run offset, not one per sequence
-            return (gEvtNum>=(gConf.GetFirstEvt()+evtEndCurSeq));
+            return (gEvtNum>=evtEndCurSeq);
         }
     } else {
         return false;
     }
 }
 
-#ifdef USE_RTOS_TIMER
+#ifdef USE_RTOS
 void stopTicker(rtos::RtosTimer* tik) {
     if (tik!=0) {
         tik->stop();
@@ -435,7 +443,7 @@
 }
 #endif
 
-#ifdef USE_RTOS_TIMER
+#ifdef USE_RTOS
 float resetTicker(rtos::RtosTimer* tik, const float timSec,
                   const float maxTimSec) {
     if (tik!=0) {
@@ -470,16 +478,16 @@
 }
 
 void ResetAllTickers() {
-#ifdef USE_RTOS_TIMER
+#ifdef USE_RTOS
     const float ftp = resetTicker(gForceTicker, gConf.GetForceTrigPeriod(),
                                   kAbsMaxTimer);
-    wait_ms(131); // make it less likely for multiple triggers to fire too close together
+    Thread::wait(131); // make it less likely for multiple triggers to fire too close together
     const float hbp = resetTicker(gHeartbeatTicker, gConf.GetHeartbeatPeriod(),
                                   kAbsMaxTimer);
-    wait_ms(173); // make it less likely for multiple triggers to fire too close together
+    Thread::wait(173); // make it less likely for multiple triggers to fire too close together
     const float cwp = resetTicker(gCommWinTicker, gConf.GetCommWinPeriod(),
                                   kCommWinLongPrdTk);
-    wait_ms(169); // make it less likely for multiple triggers to fire too close together
+    Thread::wait(169); // make it less likely for multiple triggers to fire too close together
     const float pcp = resetTicker(gPowerCheckTicker, gConf.GetVoltCheckPeriod(),
                                   kAbsMaxTimer);
 #else
@@ -511,14 +519,34 @@
     OpenCommWin();
     while (true) {
         led3 = 1; led4=1;
+#ifdef USE_RTOS
+        Thread::wait(500);
+#else
         wait(0.5);
+#endif
         led3 = 0; led4=0;
+#ifdef USE_RTOS
+        Thread::wait(500);
+#else
         wait(0.5);
+#endif
         // don't kick the watchdog
         // if we do, the station is unrecoverable without physical access
     }
 }
 
+
+void InitSDCard() {
+#ifdef DEBUG
+    printf("initializing SD card..\r\n");
+#endif
+    // initialize the SD card. this should prevent the issue with
+    // seq 0 being overwritten upon power up or the SD card first
+    // being insterted
+    sd.disk_initialize();
+}
+
+
 int main() {
     // a failsafe
     Watchdog::kick(WDFAILSAFE);
@@ -528,32 +556,22 @@
 #if defined(SSNOTIFY) || defined(DEBUG)
         printf("main: start\r\n");
 #endif
+#ifdef USE_RTOS
+        led1=1; Thread::wait(200);
+        led1=0; led2=1; Thread::wait(200);
+        led2=0; led3=1; Thread::wait(200);
+        led3=0; led4=1; Thread::wait(200);
+#else
         led1=1; wait(0.2);
         led1=0; led2=1; wait(0.2);
         led2=0; led3=1; wait(0.2);
         led3=0; led4=1; wait(0.2);
+#endif
         led4=0;
     }
 
-#ifdef DEBUG
-    printf("initializing SD card..\r\n");
-#endif
-    // initialize the SD card. this should prevent the issue with
-    // seq 0 being overwritten upon power up or the SD card first
-    // being insterted
-    sd.disk_initialize();
-    
-    /*
-    {
-        uint32_t nfls=0; float totkb=0;
-        SnSDUtils::GetDirProps(SnSDUtils::kSDdir, nfls, totkb);
-        totkb /= 1e3; // KB
-#ifdef DEBUG
-        printf("nfiles=%u, tb=%g kb (%g)\r\n",nfls,totkb,totkb/1024.0);
-#endif
-    }
-    */
-    
+    SnSDUtils::fgDoInit = &InitSDCard;
+        
 #ifdef DEBUG
     printf("making comm objects\r\n");
 #endif
@@ -572,19 +590,23 @@
 #endif
 #endif
 #ifdef ENABLE_SBD_COMM
-    //gComms[comi++] = new SnCommSBD(&gSBDport, &gCpu);
-    gComms[comi++] = new SnCommWinSBD(&gSBDport, &gCpu);
+    gComms[comi++] = new SnCommWinSBD(&gSBDport);
 #endif
 #ifdef ENABLE_USB_COMM
-    //gComms[comi++] = new SnCommUsb(&gCpu);
     gComms[comi++] = new SnCommWinUsb(&gCpu);
 #endif
 
 #ifdef DEBUG
     printf("made comm objects\r\n");
 #endif
-
-#ifdef USE_RTOS_TIMER
+    
+    if (comi!=kNcomms) {
+        error("comi=[%hhu] != kNcomms=[%hhu]\r\n",
+            comi, kNcomms);
+        // will die here with blue lights of death
+    }
+    
+#ifdef USE_RTOS
     gForceTicker        = new rtos::RtosTimer(&procForceTrigger);
     gHeartbeatTicker    = new rtos::RtosTimer(&procHeartbeat);
     gCommWinTicker      = new rtos::RtosTimer(&procCommWin);
@@ -592,7 +614,6 @@
 #endif    
     
     led2=1;
-    //wait_ms(100);
     
 #ifdef DEBUG
     printf("\n\n\n\n\n\nstarting\r\n");
@@ -607,7 +628,7 @@
 #endif
     gLastCommWin = time(0); // prevent comm win proc
     
-#ifdef USE_RTOS_TIMER
+#ifdef USE_RTOS
     gForceTicker->stop();
 #else
     gForceTicker.detach();
@@ -623,7 +644,7 @@
 #ifdef DEBUG
     printf("call OpenCommWin\r\n");
 #endif
-    OpenCommWin(true); // alwasy configure, even if no new config
+    OpenCommWin(true, true); // alwasy configure, even if no new config
     
     // get ready to trigger
     PIN_spi.format( 16, 1 ); // change to data readout format
@@ -633,7 +654,6 @@
     
     // the main event loop. wait for triggers in SendClock
     AreCardsPowered(true); // TODO: should this be an if?
-    gTrgTimer.start();
     register int32_t etms=0; // time between written events
     while( true )
     {
@@ -647,6 +667,13 @@
         printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false");
         printf("readingout=%d\r\n",(int)gReadingOut);
 #endif
+        if (gFirstEvt) {
+            SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(),
+                                            gClkSet,
+                                            true);
+            gThmTrgTimer.reset(); gThmTrgTimer.start();
+            gAllTrgTimer.reset(); gAllTrgTimer.start();
+        }
         PIN_lockRegisters = 0; // allow data to come from DFPGA
         WaitTrigAndSendClock();
         PIN_lockRegisters = 1; // block registers during readout
@@ -660,9 +687,14 @@
 
         if (gReadingOut) {
             
-            const int32_t ttms = gTrgTimer.read_ms(); // time since last trigger
-            gTrgTimer.reset(); gTrgTimer.start();     // restart trigger timer
-            etms += ttms;
+            const int32_t ttms = gThmTrgTimer.read_ms(); // for rate calculation
+            const int32_t atms = gAllTrgTimer.read_ms(); // for throttle
+            if (gEvent.IsForcedTrg()==false) {
+                // don't reset if not a thermal trigger
+                gThmTrgTimer.reset(); gThmTrgTimer.start();
+            }
+            gAllTrgTimer.reset(); gAllTrgTimer.start();     // restart trigger timer
+            etms += atms; // time between events
             
             Watchdog::kick(); // don't reset!
                         
@@ -760,10 +792,14 @@
 #ifdef DEBUG
             printf("gOpenComWin=%s, opening\r\n",gOpenCommWin?"true":"false");
 #endif
+            SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(),
+                                            gClkSet,
+                                            false);
             OpenCommWin();
             gOpenCommWin=false;
             gFirstEvt = true;
-            gTrgTimer.reset();
+            gAllTrgTimer.reset();
+            gThmTrgTimer.reset();
             etms=0;
         } else {
 #ifdef DEBUG
@@ -780,9 +816,13 @@
 #ifdef DEBUG
             printf("seq complete. sngseq=%d\r\n",gConf.IsSingleSeqRunMode());
 #endif
+            SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(),
+                                            gClkSet,
+                                            false);
             MakeOutputFile(gConf.IsSingleSeqRunMode());
             gFirstEvt = true;
-            gTrgTimer.reset();
+            gThmTrgTimer.reset();
+            gAllTrgTimer.reset();
             etms=0;
         }
 #ifdef EVT_TIME_PROFILE
@@ -844,6 +884,11 @@
     PIN_lockRegisters = 0; // unlock so we can talk to SD card.
     SnSDUtils::WriteEventTo(SnSDUtils::GetCurFile(), gGenBuf, gEvent, gConf);
     
+    // make a copy in case we need to send it with the status
+    // (copy it because we are going to clear this event while
+    // waiting for the next trigger)
+    gEvent.CopyTo(gLastEvent);
+    
     // increment event number
     ++gEvtNum;
     
@@ -868,11 +913,16 @@
         StopRunning();
     }
     FILE* cf = SnSDUtils::OpenNewOutputFile(gConf.GetMacAddress(),
-                                            gConf.GetRun());
+                                            gConf.GetRun(),
+                                            gConf.GetFirstSeq());
     // reset event, timers, trigger counters
     ResetCountersClearEvt();
     if (cf!=0) {
+#ifdef USE_RTOS
+        Thread::wait(200);
+#else
         wait_ms(200);
+#endif
         GetAvePowerReading();
 #ifdef DEBUG
         printf("writing power. v1=%g, v2=%g, r1=%g, r2=%g, t=%u, pownum=%u\r\n",
@@ -892,6 +942,20 @@
 #endif
 }
 
+bool PowerDownCommPeriph(const SnConfigFrame::EDatPackBit type) {
+    
+    SnCommWin** cw = gComms;
+    for (uint8_t i=0; i<kNcomms; i++, cw++) {
+        if ((*cw)==0) {
+            continue;
+        } else if ((*cw)->GetCommType()==type) {
+            return (*cw)->PowerDown(gConf.GetTimeoutTime(time(0),
+                                    gConf.GetCommWinConnectTO()));
+        }
+    }
+    return false;
+}
+
 //
 // power stuff
 //
@@ -914,31 +978,94 @@
         afarpb = SnConfigFrame::kAfarComWin;
     }
     // TODO: turn on amps individually, when that's possible
+    
+    // change cards power
+#ifdef DEBUG
+    printf("setting cards pin power\r\n");
+#endif
     PIN_turn_on_system = gConf.GetPowPinSetting(cardpb);
+#ifdef USE_RTOS
+    Thread::wait(10);
+#else
     wait_ms(10);
+#endif
+    // change amps power
+#ifdef DEBUG
+    printf("setting amps pin power\r\n");
+#endif
     PIN_turn_on_amps = gConf.GetPowPinSetting(ampspb);
+#ifdef USE_RTOS
+    Thread::wait(10);
+#else
     wait_ms(10);
-    PIN_iridSbd_power = (kIridAfarPwrSame)
+#endif
+    // change iridium power
+    // power down periph if going from on to off
+    const bool iridToOn = (kIridPwrFromAfar) ?
+        gConf.IsPoweredFor(afarpb) :
+        gConf.IsPoweredFor(iridpb);
+    const bool iridFromOn = PIN_iridSbd_power.read()==
+        (kIridPwrFromAfar ? gConf.GetPowPinSetting(afarpb, true)
+                          : gConf.GetPowPinSetting(iridpb, true));
+    if ( iridFromOn && (iridToOn==false) ) {
+#ifdef DEBUG
+        printf("calling PowerDown for Iridium\r\n");
+#endif
+        PowerDownCommPeriph(SnConfigFrame::kIrid);
+    }
+#ifdef DEBUG
+    printf("setting iridium pin power\r\n");
+#endif
+    PIN_iridSbd_power = (kIridPwrFromAfar)
         ? gConf.GetPowPinSetting(iridpb, false) // leave the iridium relay off. use afar relay.
         : gConf.GetPowPinSetting(iridpb);
+#ifdef USE_RTOS
+    Thread::wait(10);
+#else
     wait_ms(10);
+#endif
+    // change ethernet PHY port power
 #ifdef DEBUG
     printf("afar pin=%d, com powsetting=%d\r\n",PIN_afar_power.read(),
         gConf.GetPowPinSetting(afarpb));
 #endif
-    if (gConf.IsPoweredFor(afarpb)) {
+    if (gConf.IsPoweredFor(afarpb) ||
+        (kIridPwrFromAfar && gConf.IsPoweredFor(iridpb)) ) {
 #ifdef DEBUG
         printf("PHY cowin powering up\r\n");
 #endif
-        PHY_PowerUp(); wait(1);
+        PHY_PowerUp();
+#ifdef USE_RTOS
+        Thread::wait(1000);
+#else
+        wait(1);
+#endif
 #ifdef DEBUG
         printf("PHY cowin powered up\r\n");
 #endif
     } else {
+        // change afar power
+        // power down periph if going from on to off
+        // change afar power
+        int afon = gConf.GetPowPinSetting(afarpb, true);
+        if (kIridPwrFromAfar) {
+            // NOTE: the following only works because for the
+            // irid & afar pins, 1 = on!
+            afon |= gConf.GetPowPinSetting(iridpb, true);
+        }
+        const bool afarFromOn = (PIN_afar_power.read()==afon);
+        if (afarFromOn) {
+            PowerDownCommPeriph(SnConfigFrame::kAfar);
+        }
 #ifdef DEBUG
         printf("PHY cowin powering down\r\n");
 #endif
-        PHY_PowerDown(); wait(1);
+        PHY_PowerDown();
+#ifdef USE_RTOS
+        Thread::wait(1000);
+#else
+        wait(1);
+#endif
 #ifdef DEBUG
         printf("PHY cowin powered down\r\n");
 #endif
@@ -946,13 +1073,24 @@
 #ifdef DEBUG
     printf("PHY done\r\n");
 #endif
+#ifdef USE_RTOS
+    Thread::wait(100);
+#else
     wait_ms(100);
+#endif
+    // change afar power
     int afpp = gConf.GetPowPinSetting(afarpb);
-    if (kIridAfarPwrSame) {
+    if (kIridPwrFromAfar) {
+        // NOTE: the following only works because for the
+        // irid & afar pins, 1 = on!
         afpp |= gConf.GetPowPinSetting(iridpb);
     }
     PIN_afar_power = afpp;
-    wait(1.5); // let things power up
+#ifdef USE_RTOS
+    Thread::wait(1500);
+#else
+    wait(1.5);
+#endif
 #ifdef DEBUG
     printf("aft: pconp=%u (%08x), pcenet=%u (%08x)\r\n",
         LPC_SC->PCONP, LPC_SC->PCONP, LPC1768_PCONP_PCENET, LPC1768_PCONP_PCENET);
@@ -983,7 +1121,11 @@
     PIN_DoNotRestartAllClocks = 1;
     PIN_forceTrigger          = 0;
     PIN_heartbeat             = 0;
+#ifdef USE_RTOS
+    Thread::wait(20);
+#else
     wait_ms(20);
+#endif
     
     gCommWinChecks  = 0;
     gNcommWinChecks = gConf.GetCommWinPeriod() / kCommWinLongPrdTk;
@@ -998,7 +1140,11 @@
     
         uint16_t hi, lo;
         PIN_PLA_cs=1;
+#ifdef USE_RTOS
+        Thread::wait(4000);
+#else
         wait(4);
+#endif
         for (uint8_t pi=0; pi<kNplas; pi++) {
             if (pi < gConf.GetNumPlas()) {
                 SnConfigFrame::GetHiLoPlas(gConf.GetPla(pi), hi, lo);
@@ -1016,9 +1162,17 @@
             }
             Watchdog::kick();
         }
+#ifdef USE_RTOS
+        Thread::wait(3000);
+#else
         wait(3);
+#endif
         PIN_PLA_cs=0;
+#ifdef USE_RTOS
+        Thread::wait(3000);
+#else
         wait(3);
+#endif
     
         // DAC values
         //
@@ -1059,7 +1213,11 @@
 #ifdef DEBUG
         printf("dacs set\r\n");
 #endif
+#ifdef USE_RTOS
+        Thread::wait(20);
+#else
         wait_ms(20);
+#endif
     } else {
 #ifdef DEBUG
         printf("cards off. skipping PLA and DAC setting\r\n");
@@ -1078,7 +1236,11 @@
 
     // make new output file
     // put after PLA/DAC, in case they affect the power readings
+#ifdef USE_RTOS
+    Thread::wait(200);
+#else
     wait_ms(200);
+#endif
     MakeOutputFile();
     
     // reset tickers
@@ -1204,7 +1366,34 @@
     }
 }
 
-SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig) {
+bool IsPinPowered(const SnCommWin* cw) {
+    bool havePower = false;
+    switch (cw->GetCommType()) {
+        case SnConfigFrame::kIrid:
+            havePower = gConf.IsPoweredFor(SnConfigFrame::kIridComWin)
+                && ( (kIridPwrFromAfar)
+                      ? PIN_afar_power.read()
+                      : PIN_iridSbd_power.read() ==
+                    gConf.GetPowPinSetting(SnConfigFrame::kIridComWin));
+            break;
+        case SnConfigFrame::kAfar:
+            havePower = gConf.IsPoweredFor(SnConfigFrame::kAfarComWin)
+                && (PIN_afar_power.read() ==
+                    gConf.GetPowPinSetting(SnConfigFrame::kAfarComWin));
+            break;
+        case SnConfigFrame::kUSB:
+            havePower = true; // USB always on (for now)
+            break;
+        case SnConfigFrame::kSDcard: // shouldn't happen. skip it
+        default: // unknown.. skip it
+            break;
+    };
+    return havePower;
+}
+
+
+SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig,
+                                      const bool isStartupWin) {
     // loop through each comm mode:
     //  a) try to connect
     //  b) if connected, listen for config
@@ -1231,7 +1420,7 @@
 #endif
 
     StopAllTickers();
-
+    
     if (gConf.GetCommWinDuration()==0) {
         // TODO: set min so this is not possible
         res = SnCommWin::kOkNoMsg;
@@ -1252,16 +1441,19 @@
         printf("curfile=%p, filename=%s\r\n",SnSDUtils::GetCurFile(),
             SnSDUtils::GetCurFileName());
 #endif
-        PIN_lockRegisters = 0; // unlock so we can talk to SD card.
+        
+        if (isStartupWin==false) {
+            PIN_lockRegisters = 0; // unlock so we can talk to SD card.
 #ifdef DEBUG
-        printf("closing output file\r\n");
+            printf("closing output file\r\n");
 #endif
-        SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile());
+            SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile());
 #ifdef DEBUG
-        printf("open existing file (%d)\r\n",strlen(SnSDUtils::GetCurFileName()));
+            printf("open existing file (%d)\r\n",strlen(SnSDUtils::GetCurFileName()));
 #endif
-        SnSDUtils::OpenExistingFile(SnSDUtils::GetCurFileName(), true, false);
-        
+            SnSDUtils::OpenExistingFile(SnSDUtils::GetCurFileName(), true, false);
+        }
+
 #ifdef DEBUG
         printf("setting power\r\n");
 #endif
@@ -1269,7 +1461,9 @@
         SetPower(true);
         
         // time to recount files for the status update
-        SnStatusFrame::fgRecalcFiles = true;
+        // for the startup win, don't access SD card in case we
+        // rebooted due to a problem with the SD card
+        SnStatusFrame::fgRecalcFiles = !isStartupWin;
         
 #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM)
         bool doTwitter = false;
@@ -1300,56 +1494,47 @@
             // port is powered down, making an Ethernet obejct
             // (done in netif) will stall forever waiting for the clock.
             // Do it here to keep all PIN usage in main.cpp
-            bool havePower=false;
-            switch ((*cw)->GetCommType()) {
-                case SnConfigFrame::kIrid:
-                    havePower = gConf.IsPoweredFor(SnConfigFrame::kIridComWin)
-                        && ( (kIridAfarPwrSame)
-                              ? PIN_afar_power.read()
-                              : PIN_iridSbd_power.read() ==
-                            gConf.GetPowPinSetting(SnConfigFrame::kIridComWin));
-                    break;
-                case SnConfigFrame::kAfar:
-                    havePower = gConf.IsPoweredFor(SnConfigFrame::kAfarComWin)
-                        && (PIN_afar_power.read() ==
-                            gConf.GetPowPinSetting(SnConfigFrame::kAfarComWin));
-                    break;
-                case SnConfigFrame::kUSB:
-                    havePower = true; // USB always on (for now)
-                    break;
-                case SnConfigFrame::kSDcard: // shouldn't happen. skip it
-                default: // unknown.. skip it
-                    break;
-            };
+            const bool havePower=IsPinPowered(*cw);
             if (havePower==false) {
                 continue;
             }
-
+            
+            // always apply safety nets to connection and listen so
+            // that we don't accidently shut down comms (i.e. with
+            // connectTO or listnTO being 0)
+            gConf.ApplyConnectListenSafetyNets();
             const uint32_t conto = 
-                (gConf.GetCommWinDuration() < (*cw)->GetConnectTimeout()) ?
-                 gConf.GetCommWinDuration() : (*cw)->GetConnectTimeout();
+                (gConf.GetCommWinDuration() < gConf.GetCommWinConnectTO()) ?
+                 gConf.GetCommWinDuration() : gConf.GetCommWinConnectTO();
             const uint32_t listo = 
-                (gConf.GetCommWinDuration() < (*cw)->GetListenTimeout()) ?
-                 gConf.GetCommWinDuration() : (*cw)->GetListenTimeout();
-        
+                (gConf.GetCommWinDuration() < gConf.GetCommWinListenTO()) ?
+                 gConf.GetCommWinDuration() : gConf.GetCommWinListenTO();
+            
             // update power reading in case we want to send it in status
             GetAvePowerReading();
 
             // open window and (mabye) send status update
 #ifdef DEBUG
             printf("calling OpenWindow. ss=%d\r\n",(int)(*ss));
+            printf("conto=%u, listo=%u, dur=%u, connTO=%u, lisTO=%u\r\n",
+                conto,listo,gConf.GetCommWinDuration(),
+                gConf.GetCommWinConnectTO(), gConf.GetCommWinListenTO());
             printf("gtt=%u, ct=%d, lcw=%d, dur=%u\r\n",gConf.GetTimeoutTime(gLastCommWin,conto),
                 time(0), gLastCommWin, gConf.GetCommWinDuration());
 #endif
             const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow(
-                gConf.GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gEvent, gPower,
+//                gConf.GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gEvent, gPower,
+                gConf.GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gLastEvent, gPower,
                 SnSDUtils::GetCurSeqNum(), thmrate, evtrate,
                 gGenBuf);
             if (conres>=SnCommWin::kConnected) {
                 Watchdog::kick(); // don't reset!
                 // connected. listen for config
                 *ss = false; // don't send status next time
-
+                
+                // clear watchdog reset bit now that we've told someone
+                Watchdog::clearResetFlag();
+                
 #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM)
                 if ((*cw)->GetCommType()==SnConfigFrame::kAfar) {
                     // if we connected by Afar
@@ -1373,17 +1558,34 @@
                     // send data if need be (files, some events, etc)
                     const uint32_t winto = gConf.GetTimeoutTime(gLastCommWin, 
                                                          gConf.GetCommWinDuration());
-                    const uint32_t gtt = gConf.IsObeyingTimeout() ? winto : 0;
+                    //const uint32_t gtt = gConf.IsObeyingTimeout() ? winto : 0;
+                    
+                    // check if there are any requests before sending data
+                    if (gConf.IsWaitingHndShkBeforeSendData()) {
+                        // send handshake request
+                        (*cw)->SendHndshkReq(gGenBuf, winto);
+                        // wait for response
+                        uint8_t hndshk(0); uint32_t hndshkLen(0);
+                        res = (*cw)->WaitHandshake(gConf, winto, gGenBuf, gBufSize, hndshk,
+                                                   &hndshkLen);
+                        // handle response
+                        if (SnCommWin::kOkWithMsg==res) {
+                            res = (*cw)->HandleHandshake(SnSDUtils::GetCurFile(), 
+                                      SnSDUtils::GetCurFileName(),
+                                      gConf, gLastEvent, gPower, gGenBuf, gBufSize,
+                                      winto, hndshk, hndshkLen);
+                        }
+                    }
                     if (gConf.GetCommSendData()!=0) {
 #ifdef DEBUG
-                        printf("sending data, gtt=%u. lcw=%u, dur=%u, obey=%s\r\n",
-                            gConf.GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration()),
+                        printf("sending data, winto=%u. lcw=%u, dur=%u, obey=%s\r\n",
+                            winto,
                             gLastCommWin, gConf.GetCommWinDuration(),
                             gConf.IsObeyingTimeout() ? "true" : "false");
 #endif
 
-                        res = (*cw)->SendData(gConf, gEvent, gPower, gGenBuf, gBufSize,
-                                              gtt, gConf.GetCommWinDuration());
+                        res = (*cw)->SendData(gConf, gLastEvent, gPower, gGenBuf, gBufSize,
+                                              winto);
                     } else {
                         // don't send anything
                         res = cfgres;
@@ -1395,6 +1597,7 @@
                     break;
                 }
             } else {
+                // OpenWindow did not connect
                 (*cw)->CloseConn(gConf.GetTimeoutTime(gLastCommWin, listo));
             } // if connected
             
@@ -1407,26 +1610,31 @@
             if ((*cw)==0) {
                 continue;
             }
+            const bool havePower=IsPinPowered(*cw);
+            if (havePower==false) {
+                continue;
+            }
+
             // check Iridium time
-            // add on the SBD connect timeout so that we have a
-            // chance to set the clock even if we never got a response from UCI
-            const uint32_t extraTime = gLastCommWin + kConnectSBDTO;
             if ((*cw)->GetCommType()==SnConfigFrame::kIrid) {
 #ifdef DEBUG
                 printf("try to set iridium time\r\n");
 #endif
                 // set the clock before closing connection
                 const bool con = 
-                    (*cw)->Connect(gConf.GetTimeoutTime(extraTime,
+                    (*cw)->Connect(gConf.GetTimeoutTime(gLastCommWin,
                         gConf.GetCommWinDuration()));
                 if (con) {
-                    const uint32_t nt = (*cw)->TrySetSysTimeUnix(
-                        gConf.GetTimeoutTime(extraTime,gConf.GetCommWinDuration()));
+                    uint32_t prvTime(0), setTime(0);
+                    const bool settime = (*cw)->TrySetSysTimeUnix(
+                        gConf.GetTimeoutTime(gLastCommWin,
+                                             gConf.GetCommWinDuration()),
+                        prvTime, setTime);
+                    gClkSet.SetClocks(prvTime, setTime);
                 }
             }
-            // close the connection
-            (*cw)->CloseConn(gConf.GetTimeoutTime(extraTime,gConf.GetCommWinDuration()));
-            Watchdog::kick(); // don't reset!
+            // close the connection -- this must be why Twitter didn't work!
+            //(*cw)->CloseConn(gConf.GetTimeoutTime(gLastCommWin,gConf.GetCommWinDuration()));
             // after normal Afar connection closed, try to tweet
 #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM)
             if ((*cw)->GetCommType()==SnConfigFrame::kAfar) {
@@ -1448,7 +1656,7 @@
 #endif
                     const SnCommWin::ECommWinResult conres = gTwit->OpenWindow(
                         gConf.GetTimeoutTime(gLastCommWin, conto), false, gConf,
-                        gEvent, gPower,
+                        gLastEvent, gPower,
                         SnSDUtils::GetCurSeqNum(), thmrate, evtrate,
                         gGenBuf);
                     if (conres>=SnCommWin::kConnected) {
@@ -1457,9 +1665,22 @@
                                      gConf.GetTimeoutTime(time(0), listo));
                     }
                 }
-            }
+            } // end tweet block
 #endif
+            Watchdog::kick(); // don't reset!
+        } // end loop: check time, tweet, etc
+        
+        // close connections
+        const uint32_t extraDiscTime = gLastCommWin + gConf.GetCommWinConnectTO();
+        cw = gComms;
+        for (uint8_t i=0; i<kNcomms; i++, cw++) {
+            if ((*cw)==0) {
+                continue;
+            } else {
+                (*cw)->CloseConn(gConf.GetTimeoutTime(extraDiscTime, gConf.GetCommWinDuration()));
+            }
         }
+
     } // if duration >0
     
     /* not working. must use DEFCONF.DAT to change IP's.
@@ -1473,6 +1694,25 @@
         }
     }
     */
+
+    
+    // check if we missed too many consecutive connections
+    if (res<=SnCommWin::kAllFails) {
+        ++gConsecCommFails;
+#ifdef DEBUG
+        printf("gConsecCommFails=%hu, kMaxConsecCommFails=%hu\r\n",
+            gConsecCommFails,kMaxConsecCommFails);
+#endif                    
+        if (gConsecCommFails>kMaxConsecCommFails) {
+#ifdef DEBUG
+            printf("rebooting\r\n");
+#endif                    
+            // goodbye cruel world, it's over. walk on by...
+            mbed_reset();
+        }
+    } else {
+        gConsecCommFails=0;
+    }
     
     // (probably) power down comms and power up cards,amps
     SetPower(false);