Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Revision:
84:80b15993944e
Parent:
76:f8383f0292c2
Child:
97:9f3fe603e8b5
--- a/main.cpp	Mon Feb 23 03:04:39 2015 +0000
+++ b/main.cpp	Fri Oct 30 04:49:40 2015 +0000
@@ -6,22 +6,7 @@
 #include "Watchdog.h"
 Watchdog::SnKickStarter gKickStarter(WDFAILSAFE);
 
-//#define DISABLE_CONFIG_SAFETYNETS
-
-// CHIPBOARD is defined in SnConstants.h
-
-#define ENABLE_AFAR_COMM
-#define ENABLE_SBD_COMM
-//#define ENABLE_USB_COMM
-//#define ENABLE_AFAR_TWITTER
-
-//#define USE_RTOS // change USE_RTOS in CommConstants and EthernetPower also
-//#define USE_ETH_INTERFACE
-//#define EVT_TIME_PROFILE
-//#define DEBUG
-//#define SSNOTIFY
-#define USE_MODSERIAL
-
+// CHIPBOARD is defined in SnPreCompOptions.h
 
 #include <stdint.h>
 #include "SnConstants.h"
@@ -37,6 +22,10 @@
 };
 #endif
 
+#ifdef DEBUG
+#include "SnMemMonitor.h"
+#endif
+
 #include "SDFileSystem.h"
 #ifdef USE_MODSERIAL
 #define MODSERIAL_RX_BUF_SIZE 512
@@ -76,6 +65,7 @@
 #include "RtosTimer.h"
 #endif // USE_RTOS_TIMER
 #include "DS1820.h"
+#include "SnL1SingleFreqSupp.h"
 
 extern "C" void mbed_reset();
 
@@ -201,7 +191,30 @@
 SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig=false,
                                       const bool isStartupWin=false);
 void                      MakeOutputFile(const bool stopRunning=false);
-void                      SetPower(const bool isCommWin);
+bool                      IsPowerAllowedFor(const bool isCommWin,
+                                            const uint8_t devicesInUse,
+                                            const SnConfigFrame::EDatPackBit b);
+void                      SetPower(const bool isCommWin,
+                                   const uint8_t devicesInUse);
+void                      CheckPower(const bool isCommWin,
+                                     const bool saveReading=true,
+                                     const uint8_t devicesInUse=
+                                       SnConfigFrame::kIrid |
+                                       SnConfigFrame::kAfar);
+void                      CheckTemp();
+void                      UpdateTemperature();
+bool                      AreCardsPowered(const bool checkPin);
+void                      GetAvePowerReading();
+#if CHIPBOARD==SST4CH
+void                      InitTempProbe();
+#endif
+void                      ResetCountersClearEvt();
+void                      CalcRate(const uint32_t numtrgs,
+                                   const double   tottime_ms,
+                                   float&         rate);
+void                      GetRates(float& thmrate, float& evtrate);
+void                      AddToRate(const double dt, const bool isThm);
+bool                      IsSeqComplete();
 void                      procForceTrigger();
 void                      procHeartbeat();
 void                      procPowerCheck();
@@ -237,6 +250,7 @@
 static Timer          gThmTrgTimer;
 static Timer          gAdcToMBtimer;
 
+static Timer                 gSinceClkSet;
 static SnClockSetFrame       gClkSet;
 static SnSignalStrengthFrame gSigStr;
 #ifdef DISABLE_CONFIG_SAFETYNETS
@@ -245,7 +259,7 @@
 static SnConfigFrame  gConf;
 #endif // DISABLE_CONFIG_SAFETYNETS
 static SnEventFrame   gEvent;
-static SnEventFrame   gLastEvent;
+//static SnEventFrame   gLastEvent;
 static SnPowerFrame   gPower;
 static SnTempFrame    gTemperature;
 // parameters
@@ -258,13 +272,19 @@
 static volatile bool  gCheckTemp        = false; // if it should be checked
 static uint32_t       gPowNum           = 0;
 static uint32_t       gEvtNum           = 0;   // num of evt written
-static uint32_t       gTrgNum[kNumTrgs] = {0}; // num of this type of trg received
+static volatile bool  gForcedTrig       = false; // forced trigger bit
+static volatile bool  gAdcToMBflag      = false; // flag in case getting the ADC values took too long
+//static uint32_t       gTrgNum[kNumTrgs] = {0}; // num of this type of trg received
+static uint32_t       gNumThmTrigs      = 0; // number of thermal triggers counted
+static uint32_t       gNumFrcTrigs      = 0; // number of forced triggers counted
+static uint8_t        gL1ScaledownCount = 0;   // write an event every X L1 failures
 // i/o
 static time_t         gLastCommWin      = 0; // time
 static uint32_t       gCommWinChecks    = 0;
 static uint32_t       gNcommWinChecks   = 0;
 static uint16_t       gConsecCommFails  = 0;
 // heartbeat
+static SnHeartbeatFrame gHrtbt;
 static time_t         gLastHrtbt        = 0;
 static volatile bool  gHrtbtFired       = false;
 static uint32_t       gHrtbtNum         = 0;
@@ -276,16 +296,26 @@
 // this should be bigger than anything that will actually be used
 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)
-                                + 512; // breathing room
-//static const uint32_t gB64Bsize=BASE64ENC_LEN(gBufSize)+1;
-//static char           gB64Buf[gB64Bsize];
+                                + 256; // breathing room
 static char           gGenBuf[gBufSize]; // must be big enough for event or status or config!
 static SnCommWin*     gComms[kNcomms]   = { 0 }; // order => priority. afar uses RTOS, and must be made inside main
 #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM)
 static SnCommAfarNetIfTwitter* gTwit     = 0;
 #endif
+static float                   gChanFFT[kNsamps] = { 0 }; // only one chan at a time to save RAM
+// status update data cache and flags
+static SnClockSetFrame         gStTrgStartClk;
+static SnClockSetFrame         gStTrgStopClk;
+static SnPowerFrame            gStPower;
+static SnTempFrame             gStTemperature;
+static volatile bool           gStNewPower(false);
+static volatile bool           gStNewEvent(false);
+static volatile bool           gStNewHeartbeat(false);
+static volatile bool           gStNewTemperature(false);
 
-
+#ifdef EVT_TIME_PROFILE
+    Timer gProfiler;
+#endif
 
 void procForceTrigger() {
     if (gReadingOut==false && gCommWinOpen==false) {
@@ -304,8 +334,11 @@
             PIN_dataReady.read());
 #endif // ATWD4CH
 #endif
-        gEvent.SetTrgBit(kFrcTrg);
-        gEvent.SetTrgNum(++(gTrgNum[kFrcTrg]));
+        gForcedTrig = true;
+        ++gNumFrcTrigs;
+//        ++(gTrgNum[kFrcTrg]);
+//        gEvent.SetTrgBit(kFrcTrg);
+//        gEvent.SetTrgNum(++(gTrgNum[kFrcTrg]));
         //PIN_forceTrigger = 0;
         PIN_forceTrigger = 1;     // force a trigger
         PIN_forceTrigger = 0;
@@ -469,7 +502,8 @@
 }
 
 void CheckPower(const bool isCommWin,
-                const bool saveReading=true) {
+                const bool saveReading,
+                const uint8_t devicesInUse) {
 #ifdef DEBUG
     printf("CheckPower\r\n");
 #endif
@@ -521,7 +555,7 @@
         }
     }
     if (changed) {
-        SetPower(isCommWin); // TODO: This will fail if isCommWin==false? (currently not possible, but..)
+        SetPower(isCommWin, devicesInUse); // TODO: This will fail if isCommWin==false? (currently not possible, but..)
 #ifdef DEBUG
         printf("Using config %s\r\n",gConf.GetLabel());
 #endif
@@ -531,13 +565,16 @@
     gCheckPower = false;
 }
 
-void ResetCountersClearEvt() {
+void ResetCounters() {
     const uint32_t evtStartCurSeq = (SnSDUtils::GetCurSeqNum()) // no -1; start with seq=0
                                      * gConf.GetEvtsPerFile();
-    gEvent.ClearEvent();
+//    gEvent.ClearEvent();
     gEvtNum = evtStartCurSeq;
     gPowNum = evtStartCurSeq;
-    memset(gTrgNum, 0, sizeof(uint32_t)*kNumTrgs);
+//    memset(gTrgNum, 0, sizeof(uint32_t)*kNumTrgs);
+    gNumThmTrigs = 0;
+    gNumFrcTrigs = 0;
+    gForcedTrig = false;
     // reset rate counters
     gThmDtSum = 0;
     gThmNumDt = 0;
@@ -547,6 +584,12 @@
     gLastHrtbt  = 0;
     gHrtbtFired = false;
     gHrtbtNum   = 0;
+    // reset status data caches
+    gStNewPower = false;
+    gStNewEvent = false;
+    gStNewHeartbeat = false;
+    gStNewTemperature = false;
+    
 #ifdef DEBUG
     printf("Reset: gEvtNum=%u, gPowNum=%u, evtStartCS=%u\r\n",
         gEvtNum, gPowNum, evtStartCurSeq);
@@ -598,7 +641,7 @@
 
 bool IsSeqComplete() {
 #ifdef DEBUG
-    printf("IsSeqComplete: eps=%u, cntpow=%d, pow=%u, evt=%u, seq=%hu\r\n",
+    printf("IsSeqComplete: eps=%hu, cntpow=%d, pow=%u, evt=%u, seq=%hu\r\n",
         gConf.GetEvtsPerFile(), (int)gConf.IsCountingPowerReadings(),
         gPowNum, gEvtNum, SnSDUtils::GetCurSeqNum());
 #endif
@@ -788,6 +831,7 @@
 #ifdef DEBUG
     printf("Restart watchdog with time [%u] at [%u]\r\n",
         gConf.GetWatchdogPeriod(), time(0));
+    printf("Free memory = %d\r\n", FreeMem());
 #endif
     Watchdog::kick(gConf.GetWatchdogPeriod());
     
@@ -920,10 +964,16 @@
     printf("my gate = %s\r\n", gConf.GetMbedGate());
     printf("remote server = %s : %hu\r\n",
         gConf.GetRemoteServer(), gConf.GetRemotePort());
+    for (uint8_t i=0; i<SnConfigFrame::kNumDatStreams; ++i) {
+        printf("data stream %hhu (%s): connectTO=%hhu, listenTO=%hhu\r\n",
+            i, SnConfigFrame::GetDataStreamNameOfIdx(i),
+            gConf.GetCommWinConnectTOofIdx(i),
+            gConf.GetCommWinListenTOofIdx(i));
+    }
 #endif
 
     // (probably) power down comms and power up cards,amps
-    SetPower(false);
+    SetPower(false, SnConfigFrame::kIrid | SnConfigFrame::kAfar);
     // check power again to see if voltages drooped
     CheckPower(false, false);
 
@@ -931,7 +981,17 @@
     // get config
     //
 #ifdef DEBUG
+    printf("run mode\r\n");
+    printf("IsCountingPowerReadings=%d\r\n",(int)gConf.IsCountingPowerReadings());
+    printf("IsSingleSeqRunMode=%d\r\n",(int)gConf.IsSingleSeqRunMode());
+    printf("IsDualThresholdMode=%d\r\n",(int)gConf.IsDualThresholdMode());
+    printf("IsDifferentialTrigMode=%d\r\n",(int)gConf.IsDifferentialTrigMode());
+    printf("IsSBDonlyLowPwrMode=%d\r\n",(int)gConf.IsSBDonlyLowPwrMode());
+    printf("IsRunSeqListOneCommWinOnly=%d\r\n",(int)gConf.IsRunSeqListOneCommWinOnly());
+    printf("IsIgnoringSDcard=%d\r\n",(int)gConf.IsIgnoringSDcard());
+    printf("IsCommPowerSimple=%d\r\n",(int)gConf.IsCommPowerSimple());
     printf("call OpenCommWin\r\n");
+    printf("Free memory = %d\r\n", FreeMem());
 #endif
     led2 = led1 = 0; // back to "normal" for comm win
     OpenCommWin(true, true); // alwasy configure, even if no new config
@@ -956,6 +1016,7 @@
         printf("calling wait trig\r\n");
         printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false");
         printf("readingout=%d\r\n",(int)gReadingOut);
+        printf("Free memory = %d\r\n", FreeMem());
 #endif
         if (gFirstEvt) {
 #ifdef DEBUG
@@ -966,6 +1027,7 @@
                                             true);
             gThmTrgTimer.reset(); gThmTrgTimer.start();
             gAllTrgTimer.reset(); gAllTrgTimer.start();
+            gStTrgStartClk = gClkSet;
 #if CHIPBOARD==SST4CH
             // reset in case a trigger arrived before we were ready
             // this is mostly to ensure that the chip gets reset on soft
@@ -985,9 +1047,8 @@
         // PIN_readingData will be set high by SnEventFrame::ReadWaveformsSST
 #endif        // ATWD4CH
 #ifdef EVT_TIME_PROFILE
-        Timer prof;
-        prof.start();
-        int befReadWv=0, aftReadWv=0, befSaveEvt=0, aftSaveEvt=0,
+        gProfiler.start();
+        int befSaveEvt=0, aftSaveEvt=0,
             befChkPow=0, aftChkPow=0, befNewSeq=0, aftNewSeq=0, endOfLoop=0;
 #endif // EVT_TIME_PROFILE
 
@@ -997,7 +1058,8 @@
 
             const double ttms = gThmTrgTimer.read_us() / 1e3; // for rate calculation
             const double atms = gAllTrgTimer.read_us() / 1e3; // for throttle
-            if (gEvent.IsForcedTrg()==false) {
+//            if (gEvent.IsForcedTrg()==false) {
+            if (gForcedTrig) {
                 // don't reset if not a thermal trigger
                 gThmTrgTimer.reset(); gThmTrgTimer.start();
             }
@@ -1011,73 +1073,28 @@
             //
             
             // TODO: no way to check for external trigger?
-            if (gEvent.IsForcedTrg()==false) {
-                gEvent.SetTrgBit(kThmTrg);
-                gEvent.SetTrgNum(++(gTrgNum[kThmTrg]));
+            if (gForcedTrig==false) {
+//                ++(gTrgNum[kThmTrg]);
+                ++gNumThmTrigs;
                 AddToRate(ttms, true);
-            } // else already set by procForceTrigger
+            }
             
-            if ( gEvent.IsForcedTrg() || gFirstEvt ||
+            if ( gForcedTrig || gFirstEvt ||
                 (etms>=gConf.GetEvtThrtlPeriodMs()) ) {
-
-                // read data & calc CRC
-#ifdef EVT_TIME_PROFILE
-                prof.stop(); befReadWv=prof.read_us(); prof.start();
-#endif // EVT_TIME_PROFILE
-
-#if CHIPBOARD==ATWD4CH
-                // get the data to the MBED
-                gEvent.ReadWaveformsATWD(PIN_spi, PIN_selCardHiBit, PIN_selCardLoBit);
-#else
-                gEvent.ReadWaveformsSST(PIN_spi, PIN_readingData);
-                // reset in case a trigger arrived before we were ready
-                PIN_ResetChips = 1;
-//                wait_us(1);
-                PIN_ResetChips = 0;
-#endif //ATWD4CH
-
-#ifdef EVT_TIME_PROFILE
-                prof.stop(); aftReadWv=prof.read_us(); prof.start();
-#endif // EVT_TIME_PROFILE
-
-                gEvent.SetCurMbedTime();
-                
-                Watchdog::kick(); // don't reset!
-        
-#ifdef DEBUG
-                printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false");
-#endif
-                
-                /*
-                gRecentCountTime = static_cast<uint32_t>(time(0));
-                gRecentEvtNum    = gEvtNum;
-                // do start time second so that if we get only one event,
-                // the delta(t) will be less than 0 and the rates not calculated
-                if (gDoResetLastCount) {
-                    gLastCountReset = static_cast<uint32_t>(time(0)); // to calc rates
-                    gLastEventReset = gEvtNum;
-                    gDoResetLastCount = false;
-                }
-                */
-                
-#if CHIPBOARD==ATWD4CH
-                PIN_lockRegisters = 0; // done reading, unlock so we can talk to the SD card
-#else
-                // (this is redundant; it's already set low by SnEventFrame)
-                PIN_readingData   = 0; // done reading, unlock so we can talk to the SD card
-#endif // ATWD4CH
                 
 #ifdef EVT_TIME_PROFILE
-                prof.stop(); befSaveEvt=prof.read_us(); prof.start();
+    gProfiler.stop(); befSaveEvt=gProfiler.read_us(); gProfiler.start();
 #endif // EVT_TIME_PROFILE
-
+    
+                // want to keep this event. save it (and check if it passes L1)
                 SaveEvent(etms);
                 AddToRate(etms, false);
                 etms=0;
-                
+ 
 #ifdef EVT_TIME_PROFILE
-                prof.stop(); aftSaveEvt=prof.read_us(); prof.start();
+    gProfiler.stop(); aftSaveEvt=gProfiler.read_us(); gProfiler.start();
 #endif // EVT_TIME_PROFILE
+               
             } else {
 #if CHIPBOARD==SST4CH
                 // reset in case a trigger arrived before we were ready
@@ -1086,6 +1103,11 @@
 #endif
             }
 
+            // done with this event.
+            // reset flags from the "old" event
+            gForcedTrig = false;
+            gAdcToMBflag = false;
+
             led1 = 1; led4 = 0; // end signal reading out
             
         }
@@ -1095,13 +1117,19 @@
         
         if (gHrtbtFired) {
             led1 = 1; led4 = 1; // signal saving transient
+            gHrtbt.SetTime( gLastHrtbt );
+            // -1 so we start counting at 0
+            // counting inside proc so we have a record of the number of proc's
+            // even if we are saving/triggering slower than they're firing
+            gHrtbt.SetNum( (gHrtbtNum>0) ? (gHrtbtNum - 1) : 0 ); 
             SaveHeartbeat();
             gHrtbtFired=false;
+            gStNewHeartbeat = true;
             led1 = 1; led4 = 0; // end signal saving transient
         }
                 
 #ifdef EVT_TIME_PROFILE
-        prof.stop(); befChkPow=prof.read_us(); prof.start();
+        gProfiler.stop(); befChkPow=gProfiler.read_us(); gProfiler.start();
 #endif // EVT_TIME_PROFILE
         // check the power?
         if (gCheckPower) {
@@ -1110,10 +1138,12 @@
 #endif
             led1 = 1; led4 = 1; // signal saving transient
             CheckPower(false);
+            gStPower = gPower;
+            gStNewPower = true;
             led1 = 1; led4 = 0; // end signal saving transient
         }
 #ifdef EVT_TIME_PROFILE
-        prof.stop(); aftChkPow=prof.read_us(); prof.start();
+        gProfiler.stop(); aftChkPow=gProfiler.read_us(); gProfiler.start();
 #endif // EVT_TIME_PROFILE
         
         if (gCheckTemp) {
@@ -1122,6 +1152,8 @@
 #endif
             led1 = 1; led4 = 1; // signal saving transient
             CheckTemp();
+            gStTemperature = gTemperature;
+            gStNewTemperature = true;
             led1 = 1; led4 = 0; // end signal saving transient
         }
         
@@ -1134,6 +1166,7 @@
             SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(),
                                             gClkSet,
                                             false);
+            gStTrgStopClk = gClkSet;
             led1 = 0; // signal not waiting
             OpenCommWin();
             led1 = 1; // end signal not waiting
@@ -1150,7 +1183,7 @@
         }
         
 #ifdef EVT_TIME_PROFILE
-        prof.stop(); befNewSeq=prof.read_us(); prof.start();
+        gProfiler.stop(); befNewSeq=gProfiler.read_us(); gProfiler.start();
 #endif // EVT_TIME_PROFILE
         // make new seq?
         if (IsSeqComplete()) {
@@ -1162,6 +1195,7 @@
             SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(),
                                             gClkSet,
                                             false);
+            gStTrgStopClk = gClkSet;
             MakeOutputFile(gConf.IsSingleSeqRunMode());
             gFirstEvt = true;
             gThmTrgTimer.reset();
@@ -1170,14 +1204,14 @@
             led1 = 1; led2 = 0; led4 = 0; // end signal saving file
         }
 #ifdef EVT_TIME_PROFILE
-        prof.stop(); aftNewSeq=prof.read_us(); prof.start();
+        gProfiler.stop(); aftNewSeq=gProfiler.read_us(); gProfiler.start();
 #endif // EVT_TIME_PROFILE
 
 #ifdef EVT_TIME_PROFILE
-        prof.stop(); endOfLoop=prof.read_us(); prof.start();
-        printf("befReadWv=%d, aftReadWv=%d, befSaveEvt=%d, aftSaveEvt=%d, "
+        gProfiler.stop(); endOfLoop=gProfiler.read_us(); gProfiler.start();
+        printf("befSaveEvt=%d, aftSaveEvt=%d, "
             "befChkPow=%d, aftChkPow=%d, befNewSeq=%d, aftNewSeq=%d, endOfLoop=%d\r\n",
-            befReadWv, aftReadWv, befSaveEvt, aftSaveEvt,
+            befSaveEvt, aftSaveEvt,
             befChkPow, aftChkPow, befNewSeq, aftNewSeq, endOfLoop);
 #endif // EVT_TIME_PROFILE
         
@@ -1190,7 +1224,7 @@
         // reset event
         // clear after comm win, so full event can be sent with status
         // but don't clear counters or trigger bits, as
-        gEvent.ClearEvent(true);
+//        gEvent.ClearEvent(true);
     
     } // end while (true)
 
@@ -1200,20 +1234,17 @@
 // save a heartbeat tag
 //
 void SaveHeartbeat() {
-    if (gHrtbtNum>0) {
 #ifdef DEBUG
-        printf("save heartbeat #%u, time %u\r\n",
-            gHrtbtNum-1, gLastHrtbt);
+    printf("save heartbeat #%u, time %u\r\n",
+        gHrtbt.GetNum(), gHrtbt.GetTime());
 #endif
-        // save to SD
+    // save to SD
 #if CHIPBOARD==ATWD4CH
-        PIN_lockRegisters = 0; // unlock so we can talk to the SD card
+    PIN_lockRegisters = 0; // unlock so we can talk to the SD card
 #else
-        PIN_readingData   = 0; // unlock so we can talk to the SD card
+    PIN_readingData   = 0; // unlock so we can talk to the SD card
 #endif
-        SnSDUtils::WriteHeartbeatTo(SnSDUtils::GetCurFile(),
-            gLastHrtbt, gHrtbtNum-1); // -1 so it counts from 0
-    }
+    SnSDUtils::WriteHeartbeatTo(SnSDUtils::GetCurFile(), gHrtbt);
 }
 
 //
@@ -1223,31 +1254,203 @@
     // write the event
     
 #ifdef DEBUG
-    printf("save event (%u)\r\n", gEvtNum);
+    // check that the event is still the same as gLastEvent
+    /*
+    bool esame = gEvent.GetMbedTime() == gLastEvent.GetMbedTime();
+    esame &= gEvent.GetEvtNum() == gLastEvent.GetEvtNum();
+    esame &= gEvent.GetDTms() == gLastEvent.GetDTms();
+    esame &= gEvent.GetTrgNum() == gLastEvent.GetTrgNum();
+    esame &= gEvent.GetTrgBits() == gLastEvent.GetTrgBits();
+    esame &= gEvent.GetCRC() == gLastEvent.GetCRC();
+    for (uint16_t i=0; i<kTotSamps; ++i) {
+        esame &= (gEvent.GetData())[i] == (gLastEvent.GetData())[i];
+    }
+#if CHIPBOARD!=ATWD4CH
+    for (uint16_t i=0; i<kNstopBytes; ++i) {
+        esame &= (gEvent.GetStop())[i] == (gLastEvent.GetStop())[i];
+    }
+    printf("EEEEEEEE event==lastEvt = %s\r\n", (esame?"true":"false"));
+#endif
+    */
+#endif
+    
+    // ok, now we can overwrite the old gEvent data
+    // reset event
+    gEvent.ClearEvent(true, true);
+    
+    // read data & calc CRC
+#ifdef EVT_TIME_PROFILE
+    int befReadWv=0, aftReadWv=0, befWriteEvt=0, aftWriteEvt=0;
+    gProfiler.stop(); befReadWv=gProfiler.read_us(); gProfiler.start();
+#endif // EVT_TIME_PROFILE
+
+#if CHIPBOARD==ATWD4CH
+    // get the data to the MBED
+    gEvent.ReadWaveformsATWD(PIN_spi, PIN_selCardHiBit, PIN_selCardLoBit);
+#else
+    gEvent.ReadWaveformsSST(PIN_spi, PIN_readingData);
+    // reset in case a trigger arrived before we were ready
+    PIN_ResetChips = 1;
+//  wait_us(1);
+    PIN_ResetChips = 0;
+#endif //ATWD4CH
+
+#ifdef EVT_TIME_PROFILE
+    gProfiler.stop(); aftReadWv=gProfiler.read_us(); gProfiler.start();
+#endif // EVT_TIME_PROFILE
+
+    gEvent.SetCurMbedTime();
+                
+    Watchdog::kick(); // don't reset!
+        
+#ifdef DEBUG
+    printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false");
+#endif
+                
+#if CHIPBOARD==ATWD4CH
+    PIN_lockRegisters = 0; // done reading, unlock so we can talk to the SD card
+#else
+    // (this is redundant; it's already set low by SnEventFrame)
+    PIN_readingData   = 0; // done reading, unlock so we can talk to the SD card
+#endif // ATWD4CH
+                
+#ifdef DEBUG
+    printf("waveform read out. save event (%u)\r\n", gEvtNum);
 #endif
 
     // set the event number & dt
     gEvent.SetEvtNum(gEvtNum);
     gEvent.SetDTms(etms);
+    // set trigger bits
+    if (gForcedTrig) {
+        gEvent.SetTrgBit(kForced);
+//        gEvent.SetTrgNum(gTrgNum[kFrcTrg]);
+        gEvent.SetTrgNum(gNumFrcTrigs);
+    } else {
+        gEvent.SetTrgBit(kThermal);
+//        gEvent.SetTrgNum(gTrgNum[kThmTrg]);
+        gEvent.SetTrgNum(gNumThmTrigs);
+    }
+    if (gAdcToMBflag) {
+        gEvent.SetTrgBit(kAdcToMBflag);
+    }
     
+    // this is in the config too, but doesn't hurt to flip the bit
+    // in the event
+    if (gConf.IsL1TrigApplied()) {
+        gEvent.SetTrgBit(kL1TrgApplied);
+    }
+
+    // ----
+    // L1 check(s) go here!
+    bool L1okToSave = true;
+    
+#ifdef DEBUG
+    Timer l1timer;
+    l1timer.start();
+    printf("L1 single freq supp ratio = %hhu (%g)\r\n",
+        gConf.GetSingleFreqSuppRatioRaw(),
+        gConf.GetSingleFreqSuppRatio());
+#endif
+
+    // TODO: move the FFT calculation out here so that
+    // other L1's could use it too. haven't done this already
+    // in order to save RAM and not cache the whole thing when
+    // we only have one L1 cut.
+
+    // check L1 single frequency suppression cut
+    if ( gConf.IsSingleFreqSuppEnabled() ) {
+        const EL1TrigStatus passL1SingleFreqSupp = 
+            SnL1SingleFreqSupp::ProcessEvent(gEvent, gChanFFT,
+                                             gConf.GetSingleFreqSuppRatio());
+#ifdef DEBUG
+            l1timer.stop();
+            printf("L1 single freq supp took [%d] us\r\n",
+                l1timer.read_us());
+            printf("passL1SingleFreqSupp=%s\r\n",
+                passL1SingleFreqSupp==kL1Pass ? "pass"
+                    : passL1SingleFreqSupp==kL1Fail ? "fail"
+                        : "other");
+#endif
+        if (passL1SingleFreqSupp==kL1Pass) {
+            gEvent.SetTrgBit(kSingleFreqSupp);
+        } else if ( (passL1SingleFreqSupp==kL1Fail) &&
+                     gConf.IsL1TrigApplied() ) {
+            L1okToSave = false;
+        }
+        // else if kL1UnableToProcess, the bit won't get set
+        // but the event can/will be saved
+    }
+    
+    
+    // NO MORE L1 checks below here! (or the scaledown won't work)
+    // -----
+    
+#ifdef EVT_TIME_PROFILE
+    gProfiler.stop(); befWriteEvt=gProfiler.read_us(); gProfiler.start();
+#endif // EVT_TIME_PROFILE
+
     // save to SD
 #if CHIPBOARD==ATWD4CH
     PIN_lockRegisters = 0; // unlock so we can talk to the SD card
 #else
     PIN_readingData   = 0; // unlock so we can talk to the SD card
 #endif
-    SnSDUtils::WriteEventTo(SnSDUtils::GetCurFile(), gGenBuf, gEvent, gConf);
+    
+    // scale down to override L1 trigger failures
+    if ( (L1okToSave==false) && (gConf.GetL1Scaledown()!=0) ) {
+        ++gL1ScaledownCount;
+        
+        if ( gL1ScaledownCount == gConf.GetL1Scaledown() ) {
+            gL1ScaledownCount = 0;
+            L1okToSave = true;
+#ifdef DEBUG
+            printf("))) L1 scaledown!\r\n");
+#endif
+        }
+    }
+
+#ifdef DEBUG
+    printf("L1 scaledown count = %hhu, scaledown=%hhu, L1okToSave=%s\r\n",
+        gL1ScaledownCount,
+        gConf.GetL1Scaledown(),
+        L1okToSave ? "true" : "false");
+    printf("event trigger bits = ");
+    SnBitUtils::printBits(gEvent.GetTrgBits(), true);
+#endif
     
+    // always save forced triggers
+    if (L1okToSave || gForcedTrig) {
+        SnSDUtils::WriteEventTo(SnSDUtils::GetCurFile(), gGenBuf, gEvent, gConf);
+        
+        // a good event
+        gStNewEvent = true;
+        
+        // send it?
+        if ( gConf.IsCommWindowEachEvent() ) {
+#ifdef DEBUG
+            printf("COMM EACH EVENT => gOpenCommWin = true\r\n");
+#endif
+            gOpenCommWin = true;
+        }
+    }
+    
+#ifdef EVT_TIME_PROFILE
+    gProfiler.stop(); aftWriteEvt=gProfiler.read_us(); gProfiler.start();
+    printf("befReadWv=%d, aftReadWv=%d, befWriteEvt=%d, aftWriteEvt=%d\r\n",
+        befReadWv, aftReadWv, befWriteEvt, aftWriteEvt);
+#endif // EVT_TIME_PROFILE
+
     // 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);
+//    gEvent.CopyTo(gLastEvent);
     
     // increment event number
     ++gEvtNum;
     
 #ifdef DEBUG
-    printf("gEvtNum=%u\r\n",gEvtNum);
+    printf("next gEvtNum=%u\r\n",gEvtNum);
 #endif
 }
 
@@ -1275,7 +1478,7 @@
                                             gConf.GetFirstSeq(),
                                             gConf.IsSendingFilesRunSeqList());
     // reset event, timers, trigger counters
-    ResetCountersClearEvt();
+    ResetCounters();
     if (cf!=0) {
 #ifdef USE_RTOS
         Thread::wait(200);
@@ -1314,7 +1517,7 @@
             printf("calling PowerDown\r\n");
 #endif
             return (*cw)->PowerDown(gConf.GetTimeoutTime(time(0),
-                                    gConf.GetCommWinConnectTO()));
+                                    gConf.GetCommWinConnectTO(type)));
         }
     }
     return false;
@@ -1330,12 +1533,13 @@
     return gConf.GetPowPinSetting(p, true) == pin.read();
 }
 
-void ChangeCardPower(const bool isCommWin) {
+void ChangeCardPower(const bool isCommWin,
+                     const bool isOn) {
     // change cards power
     const SnConfigFrame::EPowerModeBit pbit = (isCommWin)
         ? SnConfigFrame::kCardComWin
         : SnConfigFrame::kCardDatTak;
-    const int value = gConf.GetPowPinSetting(pbit);
+    const int value = gConf.GetPowPinSetting(pbit, isOn);
 #ifdef DEBUG
     printf("setting cards pin power to %d (comm=%d)\r\n",
         value, static_cast<int>(isCommWin));
@@ -1348,12 +1552,13 @@
 #endif
 }
 
-void ChangeAmpsPower(const bool isCommWin) {
+void ChangeAmpsPower(const bool isCommWin,
+                     const bool isOn) {
     // change amps power
     const SnConfigFrame::EPowerModeBit pbit = (isCommWin)
         ? SnConfigFrame::kAmpsComWin
         : SnConfigFrame::kAmpsDatTak;
-    const int value = gConf.GetPowPinSetting(pbit);
+    const int value = gConf.GetPowPinSetting(pbit, isOn);
 #ifdef DEBUG
     printf("setting amps pin power to %d (comm=%d)\r\n",
         value, static_cast<int>(isCommWin));
@@ -1366,7 +1571,8 @@
 #endif
 }
 
-void ChangeIridPower(const bool isCommWin) {
+void ChangeIridPower(const bool isCommWin,
+                     const bool isOn) {
     // change iridium power setting
     // if going from ON to OFF, call the special
     // power down procedure, so as not to lose
@@ -1382,13 +1588,10 @@
     // these checks are complicated because the iridium might
     // be powered off the Afar (12V) relay, 
     // rather than the iridium (5V) relay
-    const bool iridToOn = (kIridPwrFromAfar) ?
-        (gConf.IsPoweredFor(abit) || gConf.IsPoweredFor(ibit)) :
-        gConf.IsPoweredFor(ibit);
     const bool iridFromOn = (kIridPwrFromAfar) ?
         IsCurrentlyPowered(abit, PIN_afar_power) :
         IsCurrentlyPowered(ibit, PIN_iridSbd_power);
-    if ( iridFromOn && (iridToOn==false) ) {
+    if ( iridFromOn && (isOn==false) ) {
 #ifdef DEBUG
         printf("calling PowerDown for Iridium\r\n");
 #endif
@@ -1396,7 +1599,7 @@
     }
     const int value = (kIridPwrFromAfar)
         ? gConf.GetPowPinSetting(ibit, false) // leave the iridium relay off. use afar relay.
-        : gConf.GetPowPinSetting(ibit);
+        : gConf.GetPowPinSetting(ibit, isOn);
 #ifdef DEBUG
     printf("setting iridium pin power to %d (comm=%d)\r\n",
         value, static_cast<int>(isCommWin));
@@ -1410,7 +1613,8 @@
     
 }
 
-void ChangeAfarPower(const bool isCommWin) {
+void ChangeAfarPower(const bool isCommWin,
+                     const bool isOn) {
     // change the AFAR relay power setting
     // also power up or down the ethernet PHY port
     // as appropriate
@@ -1424,24 +1628,19 @@
     printf("pcenet bef power: status=%d\r\n",Peripheral_GetStatus(LPC1768_PCONP_PCENET));
 #endif
     
-    const SnConfigFrame::EPowerModeBit ibit = (isCommWin)
-        ? SnConfigFrame::kIridComWin
-        : SnConfigFrame::kIridDatTak;
     const SnConfigFrame::EPowerModeBit abit = (isCommWin)
         ? SnConfigFrame::kAfarComWin
         : SnConfigFrame::kAfarDatTak;
 
     const bool afarFromOn = IsCurrentlyPowered(abit, PIN_afar_power);
-    const bool afarToOn = gConf.IsPoweredFor(abit) ||
-        (kIridPwrFromAfar && gConf.IsPoweredFor(ibit));
 
     // change ethernet PHY port power
 #ifdef DEBUG
     printf("afar pin=%d, afarFromOn=%d, afarToOn=%d\r\n",
         PIN_afar_power.read(), static_cast<int>(afarFromOn),
-        static_cast<int>(afarToOn));
+        static_cast<int>(isOn));
 #endif
-    if (afarToOn) {
+    if (isOn) {
 #ifdef DEBUG
         printf("PHY cowin powering up\r\n");
 #endif
@@ -1484,7 +1683,7 @@
 #endif
 
     // change afar power
-    const int value = gConf.GetPowPinSetting(abit, afarToOn);
+    const int value = gConf.GetPowPinSetting(abit, isOn);
     PIN_afar_power = value;
 #ifdef USE_RTOS
     Thread::wait(1500);
@@ -1499,7 +1698,25 @@
     
 }
 
-void SetPower(const bool isCommWin) {
+bool IsPowerAllowedFor(const bool isCommWin,
+                       const uint8_t devicesInUse,
+                       const SnConfigFrame::EDatPackBit b) {
+    if (isCommWin && (gConf.IsCommPowerSimple()==false)) {
+        return ( (devicesInUse & b)!=0 );
+    }
+    return true;
+}
+
+void SetPower(const bool isCommWin,
+              const uint8_t devicesInUse) {
+    // devicesInUse could really just be a second set of "power mode" bits
+    // where the bit being on means "I want to change power for this device"
+    // but then.. how to handle the possibility that the bit word contains,
+    // for example, both bits AfarDatTak and AfarComWin being on?
+    // so instead, we keep the "isCommWin" boolean which forces the separation
+    // and deviceInUse is only applied when isCommWin==true
+    //
+    // multiple devices can be specified by, e.g., kIrid | kAfar
 #ifdef DEBUG
     printf("set power. isCommWin=%s\r\n",(isCommWin)?"true":"false");
     printf("WD reset = %d\r\n",(int)Watchdog::didWatchdogReset());
@@ -1512,6 +1729,8 @@
     printf("IsPoweredFor AmpsComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kAmpsComWin));
     printf("IsPoweredFor IridComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kIridComWin));
     printf("IsPoweredFor AfarComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kAfarComWin));
+    printf("devicesInUse = %hhu\r\n", (uint8_t)devicesInUse);
+    printf("IsCommPowerSimple = %s\r\n", (gConf.IsCommPowerSimple() ? "true" : "false"));
 #endif
     
     const SnConfigFrame::EPowerModeBit cardpb = (isCommWin)
@@ -1526,28 +1745,33 @@
     const SnConfigFrame::EPowerModeBit afarpb = (isCommWin)
         ? SnConfigFrame::kAfarComWin
         : SnConfigFrame::kAfarDatTak;
-    // TODO: turn on amps individually, when that's possible
     
     //
     // FIRST turn the things off that should be off.
     // this prevents short periods of high power usage
     //
 
-    // iridium is more complicated because it might
+    const bool cardToOn = gConf.IsPoweredFor(cardpb);
+    const bool ampsToOn = gConf.IsPoweredFor(ampspb);
+
+    // these are complicated because iridium might
     // be powered off of the afar line
+    // also ignore the devices in use if we're not in a comm window
     const bool iridToOn = (kIridPwrFromAfar) ?
-        gConf.IsPoweredFor(afarpb) :
-        gConf.IsPoweredFor(iridpb);
-    const bool afarToOn = gConf.IsPoweredFor(afarpb) ||
-        (kIridPwrFromAfar && gConf.IsPoweredFor(iridpb));
+        (gConf.IsPoweredFor(afarpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kIrid)) : 
+        (gConf.IsPoweredFor(iridpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kIrid));  
+    const bool afarToOn = (kIridPwrFromAfar) ?
+        (  (gConf.IsPoweredFor(afarpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kAfar)) 
+         ||(gConf.IsPoweredFor(iridpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kIrid)) ) :
+        (gConf.IsPoweredFor(afarpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kAfar));
 
-    if (gConf.IsPoweredFor(cardpb)==false) {
+    if (cardToOn==false) {
 #ifdef DEBUG
         printf("power down cards\r\n");
 #endif
-        ChangeCardPower(isCommWin);
+        ChangeCardPower(isCommWin, cardToOn);
     }
-    if (gConf.IsPoweredFor(ampspb)==false) {
+    if (ampsToOn==false) {
 #ifdef DEBUG
         printf("power down amps\r\n");
         printf("ampspb=%d, is powered for =%d\r\n",
@@ -1557,47 +1781,47 @@
             (int)(gConf.IsPoweredFor(SnConfigFrame::kAmpsDatTak)),
             (int)(gConf.IsPoweredFor(SnConfigFrame::kAmpsComWin)));
 #endif
-        ChangeAmpsPower(isCommWin);
+        ChangeAmpsPower(isCommWin, ampsToOn);
     }
     if (iridToOn==false) {
 #ifdef DEBUG
         printf("power down irid\r\n");
 #endif
-        ChangeIridPower(isCommWin);
+        ChangeIridPower(isCommWin, iridToOn);
     }
     if (afarToOn==false) {
 #ifdef DEBUG
         printf("power down afar\r\n");
 #endif
-        ChangeAfarPower(isCommWin);
+        ChangeAfarPower(isCommWin, afarToOn);
     }
     
     //
     // THEN turn on things that want to go on
     //
-    if (gConf.IsPoweredFor(cardpb)) {
+    if (cardToOn) {
 #ifdef DEBUG
         printf("power ON cards\r\n");
 #endif
-        ChangeCardPower(isCommWin);
+        ChangeCardPower(isCommWin, cardToOn);
     }
-    if (gConf.IsPoweredFor(ampspb)) {
+    if (ampsToOn) {
 #ifdef DEBUG
         printf("power ON amps\r\n");
 #endif
-        ChangeAmpsPower(isCommWin);
+        ChangeAmpsPower(isCommWin, ampsToOn);
     }
     if (iridToOn) {
 #ifdef DEBUG
         printf("power ON iridium\r\n");
 #endif
-        ChangeIridPower(isCommWin);
+        ChangeIridPower(isCommWin, iridToOn);
     }
     if (afarToOn) {
 #ifdef DEBUG
         printf("power ON afar\r\n");
 #endif
-        ChangeAfarPower(isCommWin);
+        ChangeAfarPower(isCommWin, afarToOn);
     }
     
 #ifdef DEBUG
@@ -1917,7 +2141,8 @@
         printf("total time = %d us\r\n", gAdcToMBtimer.read_us());
 #endif
         if ( kAdcToMBtimeCut < gAdcToMBtimer.read_us() ) {
-            gEvent.SetTrgBit(kAdcToMBflag);
+//            gEvent.SetTrgBit(kAdcToMBflag);
+            gAdcToMBflag = true;
         }
         gAdcToMBtimer.reset();
         
@@ -1981,6 +2206,7 @@
 #ifdef DEBUG
     printf("config=%s\r\n", gConf.GetLabel());
     printf("thmrate=%g, evtrate=%g\r\n",thmrate,evtrate);
+    printf("Free memory = %d\r\n", FreeMem());
 #endif
 
     StopAllTickers();
@@ -2025,8 +2251,9 @@
 #ifdef DEBUG
         printf("setting power\r\n");
 #endif
-        // (probably) power down cards,amps and power up comms
-        SetPower(true);
+        // (probably) power down cards,amps
+        // don't power up comms yet (only as needed for use)
+        SetPower(true, 0);
         
         // time to recount files for the status update
         // for the startup win, don't access SD card in case we
@@ -2040,23 +2267,37 @@
 #ifdef DEBUG
         printf("start loop over comms\r\n");
 #endif
-        bool sendStat[kNcomms];
+        bool needToConnect=true; // still need to talk to the outside
+        bool sendStat[kNcomms]; // if need to send status over this peripheral
+        bool needClos[kNcomms]; // if need to call CloseConn on this peripheral
         for (uint8_t i=0; i<kNcomms; ++i) {
             sendStat[i]=true;
+            needClos[i]=true;
         }
         bool* ss = sendStat;
+        bool* nc = needClos;
         SnCommWin** cw = gComms;
-        for (uint8_t i=0; ((time(0)-gLastCommWin)<gConf.GetCommWinDuration()); ++i, ++cw, ++ss) {
+        for (uint8_t i=0; needToConnect && ((time(0)-gLastCommWin)<gConf.GetCommWinDuration());
+                     ++i, ++cw, ++ss, ++nc) {
             Watchdog::kick(); // don't reset!
             if (i==kNcomms) {
                 i=0;
                 cw = gComms;
                 ss = sendStat;
+                nc = needClos;
             }
             // skip if no comm object
             if ((*cw)==0) {
                 continue;
             }
+
+            const SnConfigFrame::EDatPackBit ctype = (*cw)->GetCommType();
+            
+            // power up for this device
+            if (gConf.IsCommPowerSimple()==false) {
+                SetPower(true, ctype);
+            }
+            
             // skip if no power for this comm
             // THIS IS VITAL! For example, if the ethernet
             // port is powered down, making an Ethernet obejct
@@ -2071,13 +2312,17 @@
             // that we don't accidently shut down comms (i.e. with
             // connectTO or listnTO being 0)
             gConf.ApplyConnectListenSafetyNets();
+            
             const uint32_t conto = 
-                (gConf.GetCommWinDuration() < gConf.GetCommWinConnectTO()) ?
-                 gConf.GetCommWinDuration() : gConf.GetCommWinConnectTO();
+                (gConf.GetCommWinDuration() < gConf.GetCommWinConnectTO(ctype)) ?
+                 gConf.GetCommWinDuration() : gConf.GetCommWinConnectTO(ctype);
             const uint32_t listo = 
-                (gConf.GetCommWinDuration() < gConf.GetCommWinListenTO()) ?
-                 gConf.GetCommWinDuration() : gConf.GetCommWinListenTO();
+                (gConf.GetCommWinDuration() < gConf.GetCommWinListenTO(ctype)) ?
+                 gConf.GetCommWinDuration() : gConf.GetCommWinListenTO(ctype);
             
+            //
+            // try to connect to the outside if we haven't yet
+            //
             // update power reading in case we want to send it in status
             GetAvePowerReading();
             
@@ -2091,18 +2336,27 @@
 
             // open window and (mabye) send status update
 #ifdef DEBUG
-            printf("calling OpenWindow. ss=%d\r\n",(int)(*ss));
+            printf("Free memory = %d\r\n", FreeMem());
+            printf("calling OpenWindow. ss=%d. ctype=%hhu (%s)\r\n",
+                (int)(*ss),(uint8_t)ctype,SnConfigFrame::GetDataStreamName(ctype));
             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());
+                gConf.GetCommWinConnectTO(ctype), gConf.GetCommWinListenTO(ctype));
+            printf("stopAt=%u, current=%d, lastComWin=%d, dt~%u\r\n",
+                gConf.GetTimeoutTime(gLastCommWin,conto),
+                time(0), gLastCommWin,
+                gConf.GetTimeoutTime(gLastCommWin,conto)-time(0));
 #endif
-            const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow(
-//                gConf.GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gEvent, gPower,
-                gConf.GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gLastEvent, gPower,
-                SnSDUtils::GetCurSeqNum(), thmrate, evtrate, gPowerOnTime, gTemperature,
-                gGenBuf);
+            
+            //
+            // open the connection and send the status update (if the
+            // status has not yet been sent over this peripheral)
+            //
+            const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow( *ss,
+                gConf, gPower, gEvent, SnSDUtils::GetCurSeqNum(), thmrate, evtrate, 
+                gPowerOnTime, gTemperature,
+                gGenBuf, gConf.GetTimeoutTime(gLastCommWin, conto));
+
 #ifdef DEBUG
             printf("conres = %d\r\n",static_cast<int>(conres));
 #endif
@@ -2110,12 +2364,13 @@
                 Watchdog::kick(); // don't reset!
                 // connected. listen for config
                 *ss = false; // don't send status next time
+                *nc = true;  // will need to close this connection
                 
                 // 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 (ctype==SnConfigFrame::kAfar) {
                     // if we connected by Afar
                     doTwitter = true;
                 }
@@ -2124,6 +2379,9 @@
 #ifdef DEBUG
                 printf("get conf gtt=%u\r\n",gConf.GetTimeoutTime(gLastCommWin, listo));
 #endif
+                //
+                // ask for a new config
+                //
                 const SnCommWin::ECommWinResult cfgres = (*cw)->GetConfig(
                     gConf, gConf.GetTimeoutTime(gLastCommWin, listo), gGenBuf, gBufSize);
 #ifdef DEBUG
@@ -2136,12 +2394,30 @@
                     printf("received config!\r\n");
                     printf("send data = %d\r\n", gConf.GetCommSendData());
 #endif
-                    // 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;
                     
+                    //
+                    // send status data -- do this after getting the config!
+                    // (avoid a situation where sending all this data causes a timeout,
+                    // thereby preventing a new config from being accepted)
+                    //
+                    res = (*cw)->SendStatusData(gConf,
+                                                gStTrgStartClk, gStTrgStopClk,
+                                                gStPower, gEvent, gStTemperature,
+                                                gHrtbt, gStNewPower, gStNewEvent, 
+                                                gStNewHeartbeat, gStNewTemperature,
+                                                gGenBuf, winto);
+#ifdef DEBUG
+                    printf("SendStatusData res=%d\r\n",
+                        static_cast<int32_t>(res));
+#endif
+                    
+                    //
                     // check if there are any requests before sending data
+                    //
                     if (gConf.IsWaitingHndShkBeforeSendData()) {
                         // send handshake request
                         (*cw)->SendHndshkReq(gGenBuf, winto);
@@ -2156,13 +2432,18 @@
                         if (SnCommWin::kOkWithMsg==res) {
                             res = (*cw)->HandleHandshake(SnSDUtils::GetCurFile(), 
                                       SnSDUtils::GetCurFileName(),
-                                      gConf, gLastEvent, gPower, gGenBuf, gBufSize,
+                                      gConf, gEvent, gPower, gGenBuf, gBufSize,
+//                                      gConf, gLastEvent, gPower, gGenBuf, gBufSize,
                                       winto, hndshk, hndshkLen);
 #ifdef DEBUG
                             printf("HandleHandshake res = %d\r\n",static_cast<int>(res));
 #endif
                         }
-                    }
+                    } // if handshake before data
+                    
+                    //
+                    // send data if need be (files, some events, etc)
+                    //
                     if (gConf.GetCommSendData()!=0) {
 #ifdef DEBUG
                         printf("sending data, winto=%u. lcw=%u, dur=%u, obey=%s\r\n",
@@ -2171,7 +2452,9 @@
                             gConf.IsObeyingTimeout() ? "true" : "false");
 #endif
 
-                        res = (*cw)->SendData(gConf, gLastEvent, gPower, gGenBuf, gBufSize,
+                        res = (*cw)->SendData(gConf, 
+//                                              gLastEvent, gPower, gGenBuf, gBufSize,
+                                              gEvent, gPower, gGenBuf, gBufSize,
                                               winto);
 #ifdef DEBUG
                         printf("SendData res = %d\r\n",static_cast<int>(res));
@@ -2180,34 +2463,109 @@
                     } else {
                         // don't send anything
                         res = cfgres;
-                    }
+                    } // if send data
 #ifdef DEBUG
                     printf("Got config!\r\n");
 #endif
                     Watchdog::kick(); // don't reset!
-                    break;
-                }
+                    
+                    // need to close this connection
+                    *nc = true;
+                    // stop trying to connect to outside
+                    // don't break immediately, so that we can close conn and
+                    // maybe tweet (pff..)
+                    needToConnect = false;
+
+                } // if config recvd ok with message
+
+                //
+                // stupid legacy twitter crap.
+                //
+                // after normal Afar connection closed, try to tweet
+#if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM)
+                if (ctype==SnConfigFrame::kAfar) {
+                    // tweet
+#ifdef DEBUG
+                    printf("for twitter: gTwit=%p, doTwitter=%d\r\n",gTwit,(int)doTwitter);
+#endif
+                    // send a twitter update
+                    if ( (gTwit!=0) && doTwitter ) {
+                        const uint32_t conto = 
+                            (gConf.GetCommWinDuration() < gTwit->GetConnectTimeout()) ?
+                             gConf.GetCommWinDuration() : gTwit->GetConnectTimeout();
+                        const uint32_t listo = 
+                            (gConf.GetCommWinDuration() < gTwit->GetListenTimeout()) ?
+                             gConf.GetCommWinDuration() : gTwit->GetListenTimeout();
+#ifdef DEBUG
+                        printf("open twit window. conto=%u, listo=%u\r\n",
+                            conto, listo);
+#endif
+                        const SnCommWin::ECommWinResult conres = gTwit->OpenWindow(
+                            gConf.GetTimeoutTime(gLastCommWin, conto), false, gConf,
+    //                        gLastEvent, gPower,
+                            gEvent, gPower,
+                            SnSDUtils::GetCurSeqNum(), thmrate, evtrate,
+                            gGenBuf);
+                        if (conres>=SnCommWin::kConnected) {
+                            Watchdog::kick(); // don't reset!
+                            gTwit->Tweet(gConf, thmrate, evtrate, gGenBuf,
+                                         gConf.GetTimeoutTime(time(0), listo));
+                        }
+                    }
+                } // end tweet block
+#endif
+
             } else {
                 // OpenWindow did not connect
                 (*cw)->CloseConn(gConf.GetTimeoutTime(gLastCommWin, listo));
+                *nc = false;
+#ifdef DEBUG
+                printf("no connect close conn. i=%d, nc=%s\r\n",
+                    (int32_t)i, (*nc) ? "true" : "false");
+#endif
             } // if connected
             
             Watchdog::kick(); // don't reset!
+
+            if (*nc) {
+                // need to close this connection
+#ifdef DEBUG
+                printf("close conn extra time. i=%d, nc=%s\r\n",
+                    (int32_t)i, (*nc) ? "true" : "false");
+#endif
+                const uint32_t extraDiscTime = gLastCommWin 
+                    + gConf.GetCommWinConnectTO((*cw)->GetCommType());
+                (*cw)->CloseConn(
+                    gConf.GetTimeoutTime(extraDiscTime, gConf.GetCommWinDuration()));
+                *nc = false;
+            }
+            
+            Watchdog::kick(); // don't reset!
         } // end loop over comms
         
+        
         // check Iridium time, send Iridium signal strength, and close the connection(s)
         cw = gComms;
-        for (uint8_t i=0; i<kNcomms; ++i, ++cw) {
+        nc = needClos;
+        for (uint8_t i=0; i<kNcomms; ++i, ++cw, ++nc) {
             if ((*cw)==0) {
                 continue;
             }
-            const bool havePower=IsPinPowered(*cw);
-            if (havePower==false) {
-                continue;
-            }
+            
+            const SnConfigFrame::EDatPackBit ctype = (*cw)->GetCommType();
+                        
+            // check Iridium time
+            if (ctype==SnConfigFrame::kIrid) {
 
-            // check Iridium time
-            if ((*cw)->GetCommType()==SnConfigFrame::kIrid) {
+                // power up for this device
+                if (gConf.IsCommPowerSimple()==false) {
+                    SetPower(true, ctype);
+                }
+                const bool havePower=IsPinPowered(*cw);
+                if (havePower==false) {
+                    continue;
+                }
+
 #ifdef DEBUG
                 printf("try to set iridium time\r\n");
 #endif
@@ -2219,68 +2577,61 @@
                 printf("totime=%u, ctime=%u\r\n",totime,time(0));
 #endif
                 const bool con = (*cw)->Connect(totime);
+                *nc = true;
+                
                 if (con) {
                     uint32_t prvTime(0), setTime(0);
                     const bool gottime = (*cw)->TrySetSysTimeUnix(
                         totime, prvTime, setTime);
                     if (gottime) {
-                        gClkSet.SetClocks(prvTime, setTime);
+                        gClkSet.SetClocks( prvTime, setTime, time(0),
+                                           gSinceClkSet.read_us() );
+                        gSinceClkSet.reset();
+                        gSinceClkSet.start();
 #ifdef DEBUG
-                        printf("sig str: totime=%u, ctime=%u\r\n",totime,time(0));
+//                        printf("sig str: totime=%u, ctime=%u\r\n",totime,time(0));
+                        printf("sig str: totime=%u, ctime=%u\r\n",totime,gClkSet.GetCurTime());
 #endif
                         // got time; now send signal strength
                         (*cw)->SendSignalStrength( gGenBuf, gSigStr, totime );
-                    }
+                    } // if got the iridium system time
+                } // if connected (again, possibly)
+            } // if iridium
+
+            if (*nc) {
+
+                // power up for this device
+                if (gConf.IsCommPowerSimple()==false) {
+                    SetPower(true, ctype);
                 }
-            }
-            // 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) {
-                // tweet
-#ifdef DEBUG
-                printf("for twitter: gTwit=%p, doTwitter=%d\r\n",gTwit,(int)doTwitter);
-#endif
-                // send a twitter update
-                if ( (gTwit!=0) && doTwitter ) {
-                    const uint32_t conto = 
-                        (gConf.GetCommWinDuration() < gTwit->GetConnectTimeout()) ?
-                         gConf.GetCommWinDuration() : gTwit->GetConnectTimeout();
-                    const uint32_t listo = 
-                        (gConf.GetCommWinDuration() < gTwit->GetListenTimeout()) ?
-                         gConf.GetCommWinDuration() : gTwit->GetListenTimeout();
+                const bool havePower=IsPinPowered(*cw);
+                if (havePower==false) {
+                    continue;
+                }
+
 #ifdef DEBUG
-                    printf("open twit window. conto=%u, listo=%u\r\n",
-                        conto, listo);
+                printf("last loop close conn. i=%d, nc=%s\r\n",
+                    (int32_t)i, (*nc) ? "true" : "false");
 #endif
-                    const SnCommWin::ECommWinResult conres = gTwit->OpenWindow(
-                        gConf.GetTimeoutTime(gLastCommWin, conto), false, gConf,
-                        gLastEvent, gPower,
-                        SnSDUtils::GetCurSeqNum(), thmrate, evtrate,
-                        gGenBuf);
-                    if (conres>=SnCommWin::kConnected) {
-                        Watchdog::kick(); // don't reset!
-                        gTwit->Tweet(gConf, thmrate, evtrate, gGenBuf,
-                                     gConf.GetTimeoutTime(time(0), listo));
-                    }
-                }
-            } // end tweet block
-#endif
-            Watchdog::kick(); // don't reset!
-        } // end loop: check time, tweet, etc
+
+                const uint32_t extraDiscTime = gLastCommWin 
+                    + gConf.GetCommWinConnectTO((*cw)->GetCommType());
+                (*cw)->CloseConn(gConf.GetTimeoutTime(extraDiscTime, gConf.GetCommWinDuration()));
+                *nc = false;
+            }
+        } // end loop: check time, close conns
         
+        /*
         // 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.
@@ -2315,7 +2666,7 @@
     }
     
     // (probably) power down comms and power up cards,amps
-    SetPower(false);
+    SetPower(false, SnConfigFrame::kIrid | SnConfigFrame::kAfar);
 
     // reset config with system powered (for DAC/PLA setting)
 #ifdef DEBUG
@@ -2335,6 +2686,7 @@
 
 #ifdef DEBUG
     printf("closing comm win at %d\r\n",(int32_t)time(0));
+    printf("Free memory = %d\r\n", FreeMem());
 #endif
 
     led2 = 0;