Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Revision:
84:80b15993944e
Parent:
76:f8383f0292c2
Child:
85:3ced48ef94c5
--- a/SnConfigFrame.h	Mon Feb 23 03:04:39 2015 +0000
+++ b/SnConfigFrame.h	Fri Oct 30 04:49:40 2015 +0000
@@ -15,8 +15,9 @@
     static const uint32_t    kMaxCommWinPrdLowPwr; // exclusive max low power comm win period (s)
     static const uint32_t    kMinCommWinDurLowPwr; // exclusive min low power comm win duration (s)
     static const uint32_t    kMaxCommWinDurLowPwr; // exclusive max low power comm win duration (s)
-    static const uint8_t     kConfLblLen=64;       // length of configuration label char array (63+'\0') (must not change!! used in i/o sizes)
-    static const uint8_t     kIPLen=16;            // length of IP string. matches MBED's Socket class (so no ipv6) (must not change!! used in i/o sizes)
+    static const uint8_t     kConfLblLenNoStrTerm=63;            // length of configuration label char array without the terminating '\0' (must not change!! used in i/o sizes)
+    static const uint8_t     kConfLblLen=kConfLblLenNoStrTerm+1; // length of configuration label char array (63+'\0') (must not change!! used in i/o sizes)
+    static const uint8_t     kIPLen=16;            // length of IP string (includes \0). matches MBED's Socket class (so no ipv6) (must not change!! used in i/o sizes)
     
 #ifdef USE_INTERFACE_CHIP
     static const char* const kDefConfFile;  // default configuration file
@@ -28,6 +29,7 @@
 #endif
 
     static const char* const kDefIPflag;    // flag to use IP default
+    static const uint32_t    kDefIPvalue;   // value to indicate use of default IP
 
     // ATWD 4channel configs
     static const uint32_t   kMaxSizeOfV1 = 
@@ -53,6 +55,34 @@
             - sizeof(uint8_t)  // no stream hi/lo pla flag
             - sizeof(uint8_t); // no num plas variable
     static const uint32_t   kMaxSizeOfV10 = kMaxSizeOfV9 + sizeof(int8_t); // add fTempCheckPeriod
+    
+    // ATWD - expanding upon V8 (previous ATWD config)
+    static const uint32_t   kMaxSizeOfV11 = kMaxSizeOfV8
+            - sizeof(uint32_t) // label length (now always 64 bytes written)
+            - (sizeof(uint32_t) - sizeof(uint16_t)) // fEvtsPerSeq from uint32_t to uint16_t
+            - sizeof(uint8_t) // remove stream hi/lo pla's (always false now)
+            - sizeof(uint8_t) // remove pack data (always done for all peripherals)
+            - sizeof(uint8_t) // remove amps on completely
+            - (4u*kIPLen) + (4u*sizeof(uint32_t)) // change IP from strings to numbers
+            - (2u*kNplasV1*sizeof(uint16_t)) // no streaming of hi/lo patterns
+            + sizeof(uint8_t) // add single freq ratio L1 trig parameter
+            + sizeof(uint8_t) // L1 scaledown
+            + sizeof(uint16_t) - sizeof(uint8_t) // change fEnableTherm from 8 bit to 16 bit to match trigger bit word in event
+            + (2u*sizeof(uint8_t)) // connect and listen TOs for Irid & Afar
+            + sizeof(uint16_t) - sizeof(uint8_t); // run mode from 8 to 16 bit integer
+
+    // SST - expanding upon V10 (previous SST config)
+    static const uint32_t   kMaxSizeOfV12 = kMaxSizeOfV10
+            - sizeof(uint32_t) // label length (now always 64 bytes written)
+            - (sizeof(uint32_t) - sizeof(uint16_t)) // fEvtsPerSeq from uint32_t to uint16_t
+            - sizeof(uint8_t) // remove pack data (always done for all peripherals)
+            - sizeof(uint8_t) // remove amps on completely
+            - (4u*kIPLen) + (4u*sizeof(uint32_t)) // change IP from strings to numbers
+            + sizeof(uint8_t) // add single freq ratio L1 trig parameter
+            + sizeof(uint8_t) // L1 scaledown
+            + sizeof(uint16_t) - sizeof(uint8_t) // change fEnableTherm from 8 bit to 16 bit to match trigger bit word in event
+            + (2u*sizeof(uint8_t)) // connect and listen TOs for Irid & Afar
+            + sizeof(uint16_t) - sizeof(uint8_t); // run mode from 8 to 16 bit integer
 
     static const uint32_t   kMaxSizeOf = kMaxSizeOfV7; // should be the biggest one
     
@@ -62,15 +92,22 @@
         kAfar   = BIT(2),
         kUSB    = BIT(3)
     };
+    static const uint8_t kNumDatStreams = 4; // ** note: need to change manually
     
     enum ESendDataBit {
         // can't use BIT(0)! (-0 = 0 => send nothing)
-        kAllFiles       =  BIT(1), // if bit=0 => send most recent file
-        kTimeout        =  BIT(2), // if bit=0 => ignore timeout
-        kDelete         =  BIT(3), // if bit=0 => do not delete sent files
-        kForceSBDdata   =  BIT(4), // if bit=0 => do not send data over SBD
-        kHnShBefSendDat =  BIT(5), // if bit=0 => do not wait for a handshake after GetConfig before calling SendData
-        kSendRunSeqList =  BIT(6), // if bit=1 and kAllFiles bit=0, send all files in the run/seq list (instead of most recent file)
+        kAllFiles       =  BIT(1),  // if bit=0 => send most recent file
+        kTimeout        =  BIT(2),  // if bit=0 => ignore timeout
+        kDelete         =  BIT(3),  // if bit=0 => do not delete sent files
+        kForceSBDdata   =  BIT(4),  // if bit=0 => do not send data over SBD
+        kHnShBefSendDat =  BIT(5),  // if bit=0 => do not wait for a handshake after GetConfig before calling SendData
+        kSendRunSeqList =  BIT(6),  // if bit=1 and kAllFiles bit=0, send all files in the run/seq list (instead of most recent file)
+        kStatSendConf   =  BIT(7),  // if bit=1, send a config with the status update data
+        kStatSendTrgTim =  BIT(8),  // if bit=1, send trigger start/stop times with the status update data
+        kStatSendPwrDat =  BIT(9),  // if bit=1, send the last power frame recorded in data taking mode with the status update
+        kStatSendEvent  =  BIT(10), // if bit=1, send the last event frame recorded in data taking mode with the status update
+        kStatSendHtbt   =  BIT(11), // if bit=1, send the last heartbeat frame recorded in data taking mode with the status update
+        kStatSendTmpDat =  BIT(12), // if bit=1, send the last temperature frame recorded in data taking mode with the status update
         kUseBits        = static_cast<int16_t>(-BIT(14)) // useful to initialize fCommSendData as a bit word
     };
     
@@ -92,7 +129,9 @@
         kDiffTrigBit    = BIT(3), // if 0, send result of each comparator on SST
         kLowPwrSBDonly  = BIT(4), // if 0, low power afar/sbd power settings same as normal. if 1, afar off and sbd on during low power mode
         kRSListOneCW    = BIT(5), // if 0, only clear run/seq list after files sent from it
-        kIgnoreSDcard   = BIT(6)  // if 0, read/write data to SD card as normal. if 1, function as though no SD card is present
+        kIgnoreSDcard   = BIT(6), // if 0, read/write data to SD card as normal. if 1, function as though no SD card is present
+        kComPwrSimple   = BIT(7), // if 0, comm periphs powered as needed during comm win. if 1, power adjusted once at start/finish of comm win
+        kCommEachEvent  = BIT(8)  // if 0, comm windows only after comm period of seconds. if 1, comm winodows also after each event that qualifies for saving to SD card
    };
     
     // i/o version
@@ -110,16 +149,17 @@
     uint32_t    fConfTime;                 // cpu config time
     uint32_t    fRun;                      // run number
     uint16_t    fFirstSeq;                 // starting sequence number
-    uint32_t    fEvtsPerSeq;               // number of events per file
-    uint8_t     fRunMode;                  // mode of running (see ERunMode)
+    uint16_t    fEvtsPerSeq;               // number of events per file
+    uint16_t    fRunMode;                  // mode of running (see ERunMode) -- changed from uint8 to uint16 with V11+
 #if CHIPBOARD==ATWD4CH
+    // in newer versions (11+), this is always false
     uint8_t     fStreamHiLoPlas;           // (1byte bool) if true, add the separated hi/lo thresh PLA patterns to the i/o
 #endif
     // data packing
     uint8_t     fWvLoseLSB;                // number of least significant bits to lose when packing waveform data
     uint8_t     fWvLoseMSB;                // number of  most significant bits to lose when packing waveform data
     uint16_t    fWvBaseline;               // global baseline to use when packing data (useful to reduce clipping on the high end)
-    uint8_t     fDatPackType;              // type of data packing. OR'd bitword: if bit 1, will pack for writing. see EDatPackBit. default: always pack (all 1's)
+    uint8_t     fDatPackType;              // type of data packing. OR'd bitword: if bit 1, will pack for writing. see EDatPackBit. default: always pack (all 1's). starting with IOVers 11+, this is always all 1's and is not settable
     // trigger setup
     uint16_t    fDAC[kNchans][kNchanDacs]; //[card id][dac id] values should be 0-4095 here (not checked tho)
 #if CHIPBOARD==ATWD4CH
@@ -127,10 +167,10 @@
     uint16_t    fPLA[kNplas];              //[pattern id] (same for each card)
 #endif
     uint8_t     fNumCardsMajLog;           // number of cards participating in the MajLogic trigger (1 to 4)
-    uint8_t     fEnableThermTrig;          // (1byte bool) whether or not to allow thermal triggers
+    uint16_t    fEnableThermTrig;          // whether or not to allow thermal triggers. as of vers 11+, now a bit word that can enable L1 triggers in addition to in-chip triggers. that means it now must be the same size as the trigger bit word in the event!
     float       fForceTrigPeriod;          // number of seconds between force triggers (0=none)
     uint16_t    fHeartBeatPeriod;          // number of seconds between heartbeats (0=none)
-    uint8_t     fAmpsOn;                   // which amps are on (bit word. uint8_t => 8 amps max)
+    //uint8_t     fAmpsOn;                   // which amps are on (bit word. uint8_t => 8 amps max). removed vers 11+, as it cannot be implemented.
     uint16_t    fEvtThrtlPeriodMs;         // throttle period to write events (ms)
     // power
     uint8_t     fPowerMode;                // power mode bit word: see EPowerModeBit
@@ -143,8 +183,8 @@
     int16_t     fCommSendData;             // data to send during comm win (=0: none, >0=send up to x events from last file until comm win closes, <0=see ESendDataBit)
     uint32_t    fCommWinPrdLowPwr;         // low power communication window period (seconds) (range enforced)
     uint32_t    fCommWinDurLowPwr;         // low power communication window duration (seconds) (range enforced)
-    uint8_t     fCommWinConnectTOMin;      // comm win connection timeout (minutes) (range enforced)
-    uint8_t     fCommWinListenTOMin;       // comm win listening timeout (minutes) (range enforced)
+    uint8_t     fCommWinConnTOMins[kNumDatStreams]; // comm win connection timeout (minutes) for each data stream (range enforced)
+    uint8_t     fCommWinListTOMins[kNumDatStreams]; // comm win listening timeout (minutes) for each data stream (range enforced)
     char        fRemoteServer[kIPLen];     // IP address of remote server (for afar)
     uint16_t    fRemotePort;               // port number of remote server (for afar)
     char        fMbedIP[kIPLen];           // IP address of this mbed
@@ -152,8 +192,13 @@
     char        fMbedGate[kIPLen];         // IP address of this mbed gateway
     // watchdog
     uint32_t    fWatchDogPeriod;           // number of seconds of inactivity for watchdog to issue a reset
+#if CHIPBOARD==SST4CH
     // temp
     int8_t      fTempCheckPeriod;          // number of minutes between temperature checks. if negative, uses parasite power. if 0, never check.
+#endif
+    // vers 11+ below
+    uint8_t     fSnglFreqRatio;            // single frequency L1 trigger parameter = max / (tot - max). [0,255] => [0.0, 1.0]
+    uint8_t     fL1Scaledown;              // save an L1 fail event every fL1Scaledown
     
     // in case of low power, store regular settings
     // these are not sent over i/o or stored in the file
@@ -168,8 +213,13 @@
     void SetSDNeedToInitFlag();
     
     static
+    bool        IsIOversForATWD(const uint8_t rv) {
+        return ( (rv<9) || (rv==11) );
+    }
+    
+    static
     uint16_t    GetTotDacsForIOVers(const uint8_t rv) {
-        if (rv<9) {
+        if ( IsIOversForATWD(rv) ) {
             return kTotDacsAtwd4ch;
         } else {
             return kTotDacsSst4ch;
@@ -178,13 +228,14 @@
     
     static
     uint16_t    GetMaxPlasForIOVers(const uint8_t rv) {
-        if (rv<9) {
+        if ( IsIOversForATWD(rv) ) {
             return kNplasV1;
         } else {
             return 0;
         }
     }
-    
+
+
     static
     uint32_t    SizeOf(const uint8_t rv,
                        const bool streamHiLoPlas,
@@ -215,23 +266,35 @@
             maxsize = kMaxSizeOfV9;
         } else if (rv==10) {
             maxsize = kMaxSizeOfV10;
+        } else if (rv==11) {
+            maxsize = kMaxSizeOfV11;
+        } else if (rv==12) {
+            maxsize = kMaxSizeOfV12;
         }
-        const int32_t lbldiff = kConfLblLen - lblLen;
-        uint32_t sz = maxsize - lbldiff;
-        if ((lbldiff!=0) && (rv>=4)) {
-            sz += 1; // the \0 at the end of the string
+        uint32_t sz = maxsize;
+        if (rv<11) {
+            const int32_t lbldiff = kConfLblLen - lblLen;
+            sz = maxsize - lbldiff;
+            if ((lbldiff!=0) && (rv>=4)) {
+                sz += 1; // the \0 at the end of the string
+            }
         }
+#if CHIPBOARD==ATWD4CH
+        if ( IsIOversForATWD(rv) ) {
+            // streaming hi/lo plas separately?
+            const uint8_t fac = (streamHiLoPlas && (rv<11)) ? 3u : 1u;
+            const int32_t nplasNotSent = GetMaxPlasForIOVers(rv) - nplas;
+            sz -= (fac*nplasNotSent);
 
-#if CHIPBOARD==ATWD4CH
-        if (rv<9) {
-            // streaming hi/lo plas separately?
+            /*
             const uint32_t mhlp = 2u*GetMaxPlasForIOVers(rv)*sizeof(uint16_t);
             const int32_t dp = (nplas-GetMaxPlasForIOVers(rv))*sizeof(uint16_t);
-            const uint8_t fac = (streamHiLoPlas) ? 3u : 1u;
+            const uint8_t fac = (streamHiLoPlas && (rv<11)) ? 3u : 1u;
             sz += (fac*dp);
-            if (streamHiLoPlas==false) {
-                sz -= mhlp;
+            if ((streamHiLoPlas==false) || (rv>=11)) {
+                sz -= mhlp; // should be * (maxPlas - nplas), right?
             }
+            */
         }
 #endif
         return sz;
@@ -252,9 +315,11 @@
     void SetDefaultMaskIP();
     void SetDefaultGateIP();
     void ApplySafetyNets();
+    void ApplyConnectListenSafetyNets(const uint8_t dataStreamIdx);
 
  public:
     SnConfigFrame(const bool applySafety=true) : fIsLowPower(false) {
+        memset(fLabel, 0, kConfLblLen);
         fgApplySafetyNets = applySafety;
         Reset();
     }
@@ -269,12 +334,14 @@
     bool     IsSBDonlyLowPwrMode() const { return ((fRunMode & kLowPwrSBDonly)!=0); }
     bool     IsRunSeqListOneCommWinOnly() const { return ((fRunMode & kRSListOneCW)!=0); }
     bool     IsIgnoringSDcard() const { return ((fRunMode & kIgnoreSDcard)!=0); }
+    bool     IsCommPowerSimple() const { return ((fRunMode & kComPwrSimple)!=0); }
+    bool     IsCommWindowEachEvent() const { return ((fRunMode & kCommEachEvent)!=0); }
     bool     IsLowPowerMode() const { return fIsLowPower; }
     const char* GetLabel() const { return fLabel; }
     uint32_t GetLabelStrLen() const { return strlen(fLabel); }
     uint32_t GetRun() const { return fRun; }
     uint16_t GetFirstSeq() const { return fFirstSeq; }
-    uint32_t GetEvtsPerFile() const { return fEvtsPerSeq; }
+    uint16_t GetEvtsPerFile() const { return fEvtsPerSeq; }
     inline
     uint16_t GetEvtThrtlPeriodMs() const { return fEvtThrtlPeriodMs; }
     float    GetForceTrigPeriod() const { return fForceTrigPeriod; }
@@ -283,18 +350,33 @@
     uint16_t GetBatVoltFromLowPwr() const { return fBatVoltFromLowPwr; }
     uint16_t GetVoltCheckPeriod() const { return fVoltCheckPeriod; }
     uint32_t GetWatchdogPeriod() const { return fWatchDogPeriod; }
+#if CHIPBOARD==SST4CH
     uint16_t GetTempCheckPeriod() const {
         const uint16_t t = (fTempCheckPeriod<0) ? (-fTempCheckPeriod) : fTempCheckPeriod;
         return t*60;
     }
     bool     IsTempUsingParasitePower() const { return (fTempCheckPeriod<0); }
+#else
+    uint16_t GetTempCheckPeriod() const { return 0; }
+#endif
+    uint8_t  GetSingleFreqSuppRatioRaw() const { return fSnglFreqRatio; }
+    inline
+    float    GetSingleFreqSuppRatio() const { return static_cast<float>(fSnglFreqRatio) / 255.0f; }
     uint16_t GetDac(const uint8_t ch, const uint8_t dn) const { return fDAC[ch][dn]; }
 #if CHIPBOARD==ATWD4CH
     uint8_t  GetNumPlas() const { return fNumPlas; }
     uint16_t GetPla(const uint8_t pn) const { return fPLA[pn]; }
 #endif
     uint8_t  GetNumCardsMajLog() const { return fNumCardsMajLog; }
-    bool     IsThermTrigEnabled() const { return fEnableThermTrig!=0; }
+//    bool     IsThermTrigEnabled() const { return fEnableThermTrig!=0; }
+    uint8_t  GetL1Scaledown() const { return fL1Scaledown; }
+    bool     IsThermTrigEnabled() const 
+       { return (fEnableThermTrig & kThermal)!=0; }
+    bool     IsSingleFreqSuppEnabled() const
+       { return (fEnableThermTrig & kSingleFreqSupp)!=0; }
+    bool     IsL1TrigApplied() const
+       { return (fEnableThermTrig & kL1TrgApplied)!=0; }
+    /*
     bool     IsEachAmpOn() const {
         bool allon=true;
         for (uint8_t i=0; (i<kNchans) && allon; i++) {
@@ -303,7 +385,7 @@
         return allon;
     }
     // TODO: allow check for individual amps, when they can be turned on individually
-    
+    */
     const char* GetRemoteServer() const { return fRemoteServer; }
     uint16_t    GetRemotePort() const { return fRemotePort; }
     const char* GetMbedIP() const { return fMbedIP; }
@@ -311,8 +393,18 @@
     const char* GetMbedGate() const { return fMbedGate; }
     uint32_t GetCommWinPeriod() const { return fIsLowPower ? fCommWinPrdLowPwr : fCommWinPeriod; }
     uint32_t GetCommWinDuration() const { return fIsLowPower ? fCommWinDurLowPwr : fCommWinDuration; }
-    uint32_t GetCommWinConnectTO() const { return (static_cast<uint32_t>(fCommWinConnectTOMin) * 60u); }
-    uint32_t GetCommWinListenTO() const { return (static_cast<uint32_t>(fCommWinListenTOMin) * 60u); }
+    uint32_t GetCommWinConnectTOofIdx(const uint8_t idx) const {
+        return (static_cast<uint32_t>( fCommWinConnTOMins[idx] ) * 60u);
+    }
+    uint32_t GetCommWinConnectTO(const SnConfigFrame::EDatPackBit b) const {
+        return GetCommWinConnectTOofIdx(IndexOfDataStream(b));
+    }
+    uint32_t GetCommWinListenTOofIdx(const uint8_t idx) const {
+        return (static_cast<uint32_t>( fCommWinListTOMins[idx] ) * 60u);
+    }
+    uint32_t GetCommWinListenTO(const SnConfigFrame::EDatPackBit b) const {
+        return GetCommWinListenTOofIdx(IndexOfDataStream(b));
+    }
     int16_t  GetCommSendData() const { return fCommSendData; }
     
     bool     IsSendingAllFiles() const
@@ -327,6 +419,18 @@
         { return (fCommSendData<0) && ((fCommSendData & kHnShBefSendDat)!=0); }
     bool     IsSendingFilesRunSeqList() const
         { return (fCommSendData<0) && ((fCommSendData & kSendRunSeqList)!=0); }
+    bool     IsStatusSendingConfig() const
+        { return (fCommSendData<0) && ((fCommSendData & kStatSendConf)!=0); }
+    bool     IsStatusSendingTrigTimes() const
+        { return (fCommSendData<0) && ((fCommSendData & kStatSendTrgTim)!=0); }
+    bool     IsStatusSendingPowerReading() const
+        { return (fCommSendData<0) && ((fCommSendData & kStatSendPwrDat)!=0); }
+    bool     IsStatusSendingEvent() const
+        { return (fCommSendData<0) && ((fCommSendData & kStatSendEvent)!=0); }
+    bool     IsStatusSendingHeartbeat() const
+        { return (fCommSendData<0) && ((fCommSendData & kStatSendHtbt)!=0); }
+    bool     IsStatusSendingTemperature() const
+        { return (fCommSendData<0) && ((fCommSendData & kStatSendTmpDat)!=0); }
     
     uint8_t GetPowerMode() const { return fPowerMode; }
     int     GetPowPinSetting(const EPowerModeBit p, const bool isOn) const {
@@ -397,7 +501,7 @@
 #ifdef DEBUG
         printf("Rv=%hhu\r\n",Rv);
 #endif
-        if (Rv>0) {
+        if ( IsIOversionOk(Rv) ) {
             
             if (IsLowPowerMode()) {
                 // the low power bit is not streamed, so we need to
@@ -405,12 +509,16 @@
                 ChangeToNormPower();
             }
             
-            uint32_t llen=kConfLblLen;
-            b           = SnBitUtils::ReadFrom(b, llen);
+            if (Rv<11) {
+                uint32_t llen=kConfLblLen;
+                b           = SnBitUtils::ReadFrom(b, llen);
 #ifdef DEBUG
-            printf("llen=%u\r\n",llen);
+                printf("llen=%u\r\n",llen);
 #endif
-            b           = SnBitUtils::ReadFrom(b, fLabel, llen);
+                b           = SnBitUtils::ReadFrom(b, fLabel, llen);
+            } else {
+                b           = SnBitUtils::ReadFrom(b, fLabel, kConfLblLen);
+            }
 #ifdef DEBUG
             printf("lbl=%s\r\n",fLabel);
 #endif
@@ -433,18 +541,33 @@
             printf("firstseq=%hu\r\n",fFirstSeq);
 #endif
             if (Rv>1) {
-                b       = SnBitUtils::ReadFrom(b, fEvtsPerSeq);
-                b       = SnBitUtils::ReadFrom(b, fRunMode);
+                if (Rv<11) {
+                    uint32_t eps(0);
+                    b       = SnBitUtils::ReadFrom(b, eps);
+                    fEvtsPerSeq = (1<<sizeof(fEvtsPerSeq))-1; // biggest value
+                    if ( eps < fEvtsPerSeq ) {
+                        fEvtsPerSeq = eps;
+                    }
+                } else {
+                    b       = SnBitUtils::ReadFrom(b, fEvtsPerSeq);
+                }
+                if (Rv<11) {
+                    uint8_t rm(0);
+                    b       = SnBitUtils::ReadFrom(b, rm);
+                    fRunMode = rm;
+                } else {
+                    b       = SnBitUtils::ReadFrom(b, fRunMode);
+                }
             } else {
                 fEvtsPerSeq = 1000;
                 fRunMode    = 0;
             }
 #ifdef DEBUG
-                printf("eps=%u\r\n",fEvtsPerSeq);
-                printf("rm=%hhu\r\n",fRunMode);
+                printf("eps=%hu\r\n",fEvtsPerSeq);
+                printf("rm=%hu\r\n",fRunMode);
 #endif
 #if CHIPBOARD==ATWD4CH
-            if (Rv<9) {
+            if ( IsIOversForATWD(Rv) && Rv<11 ) {
                 b           = SnBitUtils::ReadFrom(b, fStreamHiLoPlas);
 #ifdef DEBUG
                 printf("shilo=%d\r\n",(int)fStreamHiLoPlas);
@@ -463,10 +586,12 @@
 #ifdef DEBUG
             printf("bl=%hu\r\n",fWvBaseline);
 #endif
-            b           = SnBitUtils::ReadFrom(b, fDatPackType);
+            if (Rv<11) {
+                b           = SnBitUtils::ReadFrom(b, fDatPackType);
 #ifdef DEBUG
-            printf("dp=%hhu\r\n",fDatPackType);
+                printf("dp=%hhu\r\n",fDatPackType);
 #endif
+            }
             uint16_t* dc = &(fDAC[0][0]);
             const uint8_t ntotdacs = GetTotDacsForIOVers(Rv);
 #ifdef DEBUG
@@ -479,7 +604,7 @@
 #endif
             }
 #if CHIPBOARD==ATWD4CH
-            if (Rv<9) {
+            if ( IsIOversForATWD(Rv) ) {
                 b           = SnBitUtils::ReadFrom(b, fNumPlas);
 #ifdef DEBUG
                 printf("npla=%hhu\r\n",fNumPlas);
@@ -497,7 +622,13 @@
 #ifdef DEBUG
             printf("mj=%hhu\r\n",fNumCardsMajLog);
 #endif
-            b           = SnBitUtils::ReadFrom(b, fEnableThermTrig);
+            if (Rv<11) {
+                uint8_t e(0);
+                b       = SnBitUtils::ReadFrom(b, e);
+                fEnableThermTrig = e;
+            } else {
+                b       = SnBitUtils::ReadFrom(b, fEnableThermTrig);
+            }
 #ifdef DEBUG
             printf("thm=%d\r\n",(int)fEnableThermTrig);
 #endif
@@ -515,10 +646,13 @@
 #ifdef DEBUG
             printf("heart=%hu\r\n",fHeartBeatPeriod);
 #endif
-            b           = SnBitUtils::ReadFrom(b, fAmpsOn);
+            if (Rv<11) {
+                uint8_t ampson(0);
+                b           = SnBitUtils::ReadFrom(b, ampson);
 #ifdef DEBUG
-            printf("amps=%hhu\r\n",fAmpsOn);
+                printf("amps=%hhu (IGNORED)\r\n",ampson);
 #endif
+            }
             b           = SnBitUtils::ReadFrom(b, fEvtThrtlPeriodMs);
 #ifdef DEBUG
             printf("throt=%hu\r\n",fEvtThrtlPeriodMs);
@@ -555,7 +689,7 @@
 #endif
             b           = SnBitUtils::ReadFrom(b, fCommSendData);
 #ifdef DEBUG
-            printf("send=%d\r\n",fCommSendData);
+            printf("send=%hd\r\n",fCommSendData);
 #endif
             b           = SnBitUtils::ReadFrom(b, fCommWinPrdLowPwr);
 #ifdef DEBUG
@@ -566,17 +700,45 @@
             printf("cmdurlp=%u\r\n",fCommWinDurLowPwr);
 #endif
             if (Rv>6) {
-                b       = SnBitUtils::ReadFrom(b, fCommWinConnectTOMin);
-                b       = SnBitUtils::ReadFrom(b, fCommWinListenTOMin);
+                if (Rv>10) {
+                    // Irid first
+                    b    = SnBitUtils::ReadFrom(b, fCommWinConnTOMins[IndexOfDataStream(kIrid)]);
+                    b    = SnBitUtils::ReadFrom(b, fCommWinListTOMins[IndexOfDataStream(kIrid)]);
+                    // Afar next
+                    b    = SnBitUtils::ReadFrom(b, fCommWinConnTOMins[IndexOfDataStream(kAfar)]);
+                    b    = SnBitUtils::ReadFrom(b, fCommWinListTOMins[IndexOfDataStream(kAfar)]);
+                } else {
+                    // older versions: set them all the same
+                    uint8_t cto, lto;
+                    b    = SnBitUtils::ReadFrom(b, cto);
+                    b    = SnBitUtils::ReadFrom(b, lto);
+                    for (uint8_t i=0; i<kNumDatStreams; ++i) {
+                        fCommWinConnTOMins[i] = cto;
+                        fCommWinListTOMins[i] = lto;
+                    }
+                }
             } else {
-                fCommWinConnectTOMin = fCommWinListenTOMin = 3u;
+                for (uint8_t i=0; i<kNumDatStreams; ++i) {
+                    fCommWinConnTOMins[i] = GetDefaultConnTOMin(i);
+                    fCommWinListTOMins[i] = GetDefaultListTOMin(i);
+                }
             }
 #ifdef DEBUG
-                printf("connectTO=%hhu, listenTO=%hhu\r\n",
-                    fCommWinConnectTOMin, fCommWinListenTOMin);
+            for (uint8_t i=0; i<kNumDatStreams; ++i) {
+                printf("data stream %hhu (%s): connectTO=%hhu, listenTO=%hhu\r\n",
+                    i, GetDataStreamNameOfIdx(i),
+                    fCommWinConnTOMins[i], fCommWinListTOMins[i]);
+            }
 #endif
             if (Rv>2) {
-                b       = SnBitUtils::ReadFrom(b, fRemoteServer, kIPLen);
+                if (Rv<11) {
+                    b       = SnBitUtils::ReadFrom(b, fRemoteServer, kIPLen);
+                } else {
+                    // read the numerical value and convert to string
+                    uint32_t rip(0);
+                    b       = SnBitUtils::ReadFrom(b, rip);
+                    GetIpStrFromVal(rip, fRemoteServer);
+                }
                 if (strncmp(fRemoteServer, kDefIPflag,kIPLen)==0) {
                     SetDefaultRemoteServ();
                 }
@@ -590,21 +752,42 @@
 #ifdef DEBUG
                 printf("rport=%hu\r\n",fRemotePort);
 #endif
-                b       = SnBitUtils::ReadFrom(b, fMbedIP, kIPLen);
+                if (Rv<11) {
+                    b       = SnBitUtils::ReadFrom(b, fMbedIP, kIPLen);
+                } else {
+                    // read the numerical value and convert to string
+                    uint32_t rip(0);
+                    b       = SnBitUtils::ReadFrom(b, rip);
+                    GetIpStrFromVal(rip, fMbedIP);
+                }
                 if (strncmp(fMbedIP, kDefIPflag,kIPLen)==0) {
                     SetDefaultMbedIP();
                 }
 #ifdef DEBUG
                 printf("mbedip=%s\r\n",fMbedIP);
 #endif
-                b       = SnBitUtils::ReadFrom(b, fMbedMask, kIPLen);
+                if (Rv<11) {
+                    b       = SnBitUtils::ReadFrom(b, fMbedMask, kIPLen);
+                } else {
+                    // read the numerical value and convert to string
+                    uint32_t rip(0);
+                    b       = SnBitUtils::ReadFrom(b, rip);
+                    GetIpStrFromVal(rip, fMbedMask);
+                }
                 if (strncmp(fMbedMask, kDefIPflag,kIPLen)==0) {
                     SetDefaultMaskIP();
                 }
 #ifdef DEBUG
                 printf("mbedmask=%s\r\n",fMbedMask);
 #endif
-                b       = SnBitUtils::ReadFrom(b, fMbedGate, kIPLen);
+                if (Rv<11) {
+                    b       = SnBitUtils::ReadFrom(b, fMbedGate, kIPLen);
+                } else {
+                    // read the numerical value and convert to string
+                    uint32_t rip(0);
+                    b       = SnBitUtils::ReadFrom(b, rip);
+                    GetIpStrFromVal(rip, fMbedGate);
+                }
                 if (strncmp(fMbedGate, kDefIPflag,kIPLen)==0) {
                     SetDefaultGateIP();
                 }
@@ -618,14 +801,27 @@
 #ifdef DEBUG
             printf("watch=%u\r\n",fWatchDogPeriod);
 #endif
-            if (Rv>9) {
+#if CHIPBOARD==SST4CH
+            if ( (IsIOversForATWD(Rv)==false) && (Rv>9) ) {
                 b       = SnBitUtils::ReadFrom(b, fTempCheckPeriod);
             }
 #ifdef DEBUG
             printf("temp check period=%hhd\r\n", fTempCheckPeriod);
 #endif
+#endif
+            if (Rv>10) {
+                b       = SnBitUtils::ReadFrom(b, fSnglFreqRatio);
+#ifdef DEBUG
+                printf("single freq ratio=%hhd\r\n", fSnglFreqRatio);
+#endif
+                
+                b       = SnBitUtils::ReadFrom(b, fL1Scaledown);
+#ifdef DEBUG
+                printf("L1 scaledown=%hhd\r\n", fL1Scaledown);
+#endif
+            }
 #if CHIPBOARD==ATWD4CH
-            if (Rv<9) {
+            if ( IsIOversForATWD(Rv) ) {
                 if (fStreamHiLoPlas!=0) {
                     uint16_t hi, lo;
                     for (uint8_t j=0; j<fNumPlas; j++) {
@@ -642,6 +838,12 @@
                 }
             }
 #endif // ATWD4CH
+        } else {
+            // trying to read an invalid config version
+#ifdef DEBUG
+            printf("Cannot accept config version [%hhu]. "
+                   "Expect [%hhu].",Rv,SnConfigFrame::kIOVers);
+#endif
         }
         
         if (fgApplySafetyNets) {
@@ -666,6 +868,10 @@
         // intentionally not writing mac address here, so we don't have to read it in
         
         b           = SnBitUtils::WriteTo(b, kIOVers); // i/o version
+        
+        // first write the label, then explicitly write the trailing \0
+        // so it's for sure always there
+        /* legacy code when io vers < 11
         // account for the ending \0
         uint32_t llen = strlen(fLabel);
         static const uint32_t maxllen = kConfLblLen-1;
@@ -674,28 +880,32 @@
         }        
         b           = SnBitUtils::WriteTo(b, llen+1); // strlen + \0
         b           = SnBitUtils::WriteTo(b, fLabel, llen);
+        */
+        b           = SnBitUtils::WriteTo(b, fLabel, kConfLblLenNoStrTerm);            
         b           = SnBitUtils::WriteTo(b, char('\0'));
         b           = SnBitUtils::WriteTo(b, fConfTime);
         b           = SnBitUtils::WriteTo(b, fRun);
         b           = SnBitUtils::WriteTo(b, fFirstSeq);
-        b           = SnBitUtils::WriteTo(b, fEvtsPerSeq);
-        b           = SnBitUtils::WriteTo(b, fRunMode);
+        b           = SnBitUtils::WriteTo(b, fEvtsPerSeq); // changed to uint16 with V11+
+        b           = SnBitUtils::WriteTo(b, fRunMode);    // changed to uint16 with V11+
+/* - the option is no longer written to the config
 #if CHIPBOARD==ATWD4CH
-        if (kIOVers<9) {
+        if ( IsIOversForATWD(kIOVers) ) {
             b           = SnBitUtils::WriteTo(b, fStreamHiLoPlas);
         }
 #endif
+*/
         b           = SnBitUtils::WriteTo(b, fWvLoseLSB);
         b           = SnBitUtils::WriteTo(b, fWvLoseMSB);
         b           = SnBitUtils::WriteTo(b, fWvBaseline);
-        b           = SnBitUtils::WriteTo(b, fDatPackType);
+        //b           = SnBitUtils::WriteTo(b, fDatPackType); // removed vers 11+
         const uint16_t* dc = &(fDAC[0][0]);
         const uint8_t ntotdacs = GetTotDacsForIOVers(kIOVers);
         for (uint16_t i=0; i<ntotdacs; i++, dc++) {
             b       = SnBitUtils::WriteTo(b, *dc);
         }
 #if CHIPBOARD==ATWD4CH
-        if (kIOVers<9) {
+        if ( IsIOversForATWD(kIOVers) ) {
             b           = SnBitUtils::WriteTo(b, fNumPlas);
             const uint16_t* pl = &(fPLA[0]);
             for (uint8_t j=0; j<fNumPlas; j++, pl++) {
@@ -704,10 +914,10 @@
         }
 #endif
         b           = SnBitUtils::WriteTo(b, fNumCardsMajLog);
-        b           = SnBitUtils::WriteTo(b, fEnableThermTrig);
+        b           = SnBitUtils::WriteTo(b, fEnableThermTrig); // 16 bits in vers 11+
         b           = SnBitUtils::WriteTo(b, fForceTrigPeriod);
         b           = SnBitUtils::WriteTo(b, fHeartBeatPeriod);
-        b           = SnBitUtils::WriteTo(b, fAmpsOn);
+        //b           = SnBitUtils::WriteTo(b, fAmpsOn); removed vers 11+
         b           = SnBitUtils::WriteTo(b, fEvtThrtlPeriodMs);
         b           = SnBitUtils::WriteTo(b, fPowerMode);
         b           = SnBitUtils::WriteTo(b, fBatVoltToLowPwr);
@@ -718,19 +928,28 @@
         b           = SnBitUtils::WriteTo(b, fCommSendData);
         b           = SnBitUtils::WriteTo(b, fCommWinPrdLowPwr);
         b           = SnBitUtils::WriteTo(b, fCommWinDurLowPwr);
-        b           = SnBitUtils::WriteTo(b, fCommWinConnectTOMin);
-        b           = SnBitUtils::WriteTo(b, fCommWinListenTOMin);
-        b           = SnBitUtils::WriteTo(b, fRemoteServer, kIPLen);
+        // vers 11+, separate conn/listen timeouts for Irid and Afar
+        b           = SnBitUtils::WriteTo(b, fCommWinConnTOMins[IndexOfDataStream(kIrid)]);
+        b           = SnBitUtils::WriteTo(b, fCommWinListTOMins[IndexOfDataStream(kIrid)]);
+        b           = SnBitUtils::WriteTo(b, fCommWinConnTOMins[IndexOfDataStream(kAfar)]);
+        b           = SnBitUtils::WriteTo(b, fCommWinListTOMins[IndexOfDataStream(kAfar)]);
+        // with vers 11+, the numerical values are stored instead of strings (saves many bytes)
+        b           = SnBitUtils::WriteTo(b, GetIpValFromStr(fRemoteServer) );
         b           = SnBitUtils::WriteTo(b, fRemotePort);
-        b           = SnBitUtils::WriteTo(b, fMbedIP, kIPLen);
-        b           = SnBitUtils::WriteTo(b, fMbedMask, kIPLen);
-        b           = SnBitUtils::WriteTo(b, fMbedGate, kIPLen);
+        b           = SnBitUtils::WriteTo(b, GetIpValFromStr(fMbedIP) );
+        b           = SnBitUtils::WriteTo(b, GetIpValFromStr(fMbedMask) );
+        b           = SnBitUtils::WriteTo(b, GetIpValFromStr(fMbedGate) );
         b           = SnBitUtils::WriteTo(b, fWatchDogPeriod);
-        if (kIOVers>9) {
+#if CHIPBOARD==SST4CH
+        if ( (IsIOversForATWD(kIOVers)==false) && (kIOVers>9) ) {
             b       = SnBitUtils::WriteTo(b, fTempCheckPeriod);
         }
+#endif
+        b           = SnBitUtils::WriteTo(b, fSnglFreqRatio); // with vers 11+
+        b           = SnBitUtils::WriteTo(b, fL1Scaledown);   // with vers 11+
+
 #if CHIPBOARD==ATWD4CH
-        if (kIOVers<9) {
+        if ( IsIOversForATWD(kIOVers) ) {
             if (fStreamHiLoPlas!=0) {
                 const uint16_t* pl = &(fPLA[0]);
                 uint16_t hi, lo;
@@ -763,14 +982,15 @@
 #endif
     }
     
-    uint32_t    SizeOf(const uint8_t rv) const {
+    uint32_t    SizeOf(const uint8_t rv=SnConfigFrame::kIOVers) const {
         // returns the num of bytes needed to stream this object
         // = size of member vars + 1 for i/o version + extra PLA strings (maybe)
-        //   + length of label string
+        //   + length of label string if rv<11
+        const uint8_t lbllen = (rv<11) ? strlen(fLabel) : kConfLblLen;
 #if CHIPBOARD==ATWD4CH
-        return SizeOf(rv, fStreamHiLoPlas!=0, fNumPlas, strlen(fLabel));
+        return SizeOf(rv, fStreamHiLoPlas!=0, fNumPlas, lbllen);
 #else // SST
-        return SizeOf(rv, false,              0,        strlen(fLabel));
+        return SizeOf(rv, false,              0,        lbllen);
 #endif
     }
     
@@ -788,6 +1008,79 @@
                             uint16_t& hiPla,
                             uint16_t& loPla,
                             const bool r2l=false);
+
+    static
+    void GetIpStrFromVal(const uint32_t ip,
+                         char(& str)[kIPLen]);
+
+    static
+    uint32_t GetIpValFromStr(const char(& str)[kIPLen]);
+
+    static
+    uint8_t IndexOfDataStream(const SnConfigFrame::EDatPackBit b) {
+        switch (b) {
+            case kSDcard: return 0u;
+            case kIrid:   return 1u;
+            case kAfar:   return 2u;
+            case kUSB:    return 3u;
+            default:
+#ifdef DEBUG
+                printf("**** unknown stream bit [%u]", static_cast<uint32_t>(b));
+#endif
+                return 0;
+        };
+    }
+
+    static
+    uint8_t GetDefaultConnTOMin(const uint8_t dataStreamIdx) {
+        switch (dataStreamIdx) {
+            case kSDcard: return 1u;
+            case kIrid:   return 3u;
+            case kAfar:   return 1u;
+            case kUSB:    return 1u;
+            default:
+#ifdef DEBUG
+                printf("**** unknown stream index [%hhu]", dataStreamIdx);
+#endif
+                return 0;
+        };
+    }
+
+    static
+    uint8_t GetDefaultListTOMin(const uint8_t dataStreamIdx) {
+        return GetDefaultConnTOMin(dataStreamIdx);
+    }
+
+    static
+    const char* GetDataStreamName(const SnConfigFrame::EDatPackBit b) {
+        switch (b) {
+            case kSDcard: return "SDcard";
+            case kIrid:   return "Iridium";
+            case kAfar:   return "Afar";
+            case kUSB:    return "USB";
+            default:
+#ifdef DEBUG
+                printf("**** unknown stream bit [%u]", static_cast<uint32_t>(b));
+#endif
+                return NULL;
+        };
+    }
+
+    static
+    const char* GetDataStreamNameOfIdx(const uint8_t idx) {
+        switch (idx) {
+            case 0u: return GetDataStreamName(kSDcard);
+            case 1u: return GetDataStreamName(kIrid);
+            case 2u: return GetDataStreamName(kAfar);
+            case 3u: return GetDataStreamName(kUSB);
+            default: 
+#ifdef DEBUG
+                printf("**** unknown stream index [%hhu]", idx);
+#endif
+                return NULL;
+        };
+    }
+
 };
 
 #endif // SN_SnConfigFrame