Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Revision:
21:ce51bb0ba4a5
Parent:
18:55f1581f2ee4
Child:
23:ccf39298f205
--- a/SnCommWin.cpp	Wed Oct 03 00:22:27 2012 +0000
+++ b/SnCommWin.cpp	Wed Oct 10 05:54:12 2012 +0000
@@ -7,6 +7,11 @@
 #include "SnStatusFrame.h"
 #include "SnSDUtils.h"
 #include "SnConstants.h"
+#include "SnCRCUtils.h"
+
+#include <algorithm>
+#include <ctype.h>
+extern "C" void mbed_reset();
 
 //#define DEBUG
 
@@ -89,6 +94,7 @@
                                               const uint32_t timeout_clock,
                                               const uint32_t handshakeTimeout) {
     // nevts==0 ==> send all events
+    // handshakeTimeout is never a clock time -- always a delta(t)
     
 #ifdef DEBUG
     printf("SnCommWin::SendData file (%p), fn=%s\r\n",inf,infn);
@@ -120,13 +126,21 @@
 #endif
                     // wait for handshake
                     uint8_t hndshk=0;
-                    res = WaitHandshake(handshakeTimeout, genBuf, bsize, hndshk);
+                    res = WaitHandshake(curConf, handshakeTimeout, genBuf, bsize, hndshk);
+#ifdef DEBUG
+                    printf("res=%d, nevts=%u, isdel=%d, inf=%p, curfile=%p, hndshk=%02x\r\n",
+                        res, nevts, curConf.IsDeletingFiles(), inf,
+                        SnSDUtils::GetCurFile(), hndshk);
+#endif
                     if (    (res==SnCommWin::kOkWithMsg) // got handshake
                          && (nevts==0)                   // sent whole file
                          &&  curConf.IsDeletingFiles()   // want to delete
                          && (inf!=SnSDUtils::GetCurFile()) // not current file
                          && (hndshk==SnHeaderFrame::kHnShOkComplCode)) {  // whole file received
                         // delete it
+#ifdef DEBUG
+                        printf("deleting file %p, %s\r\n",inf,infn);
+#endif
                         SnSDUtilsWhisperer::DeleteFile(inf, infn);
                         didDel=true;
                     }
@@ -144,12 +158,15 @@
     return res;
 }
 
-SnCommWin::ECommWinResult SnCommWin::WaitHandshake(const uint32_t timeout,
+SnCommWin::ECommWinResult SnCommWin::WaitHandshake(const SnConfigFrame& conf,
+                                                   const uint32_t timeout,
                                                    char* const buf,
                                                    const uint32_t bsize,
                                                    uint8_t& hndShkCode) {
     // ensure we don't wait forever
-    const uint32_t to = (timeout>0) ? timeout : kListenTimeout;
+    const uint32_t to = ((timeout>0) && (timeout<kAbsMaxTimer)) 
+                                ? conf.GetTimeoutTime(time(0), timeout)
+                                : conf.GetTimeoutTime(time(0), kListenTimeout);
 #ifdef DEBUG
     printf("WaitHandshake, to=%u\r\n",to);
 #endif
@@ -172,6 +189,201 @@
     return SnCommWin::kOkNoMsg;
 }
 
+SnCommWin::ECommWinResult SnCommWin::GetFilename(const uint32_t timeout,
+                                                 char* const buf,
+                                                 const uint32_t namelen) {
+    // called by GetConfig upon receipt of a kMbedFilenameCode
+    
+#ifdef DEBUG
+    printf("GetMbedFile, to=%u\r\n",timeout);
+#endif
+    const int mlen = ReceiveAll(buf, namelen, timeout);
+    if (mlen>0 && static_cast<uint32_t>(mlen) == namelen) {
+        return SnCommWin::kOkWithMsg;
+    }
+    return SnCommWin::kUnexpectedRec;
+}
+
+SnCommWin::ECommWinResult SnCommWin::GetLocalFile(std::string fname,
+                                                  char* const buf,
+                                                  const uint32_t bsize,
+                                                  const uint32_t timeout) {
+    // get a file and save it locally with the specified name
+    
+    // get the header for the file
+    uint8_t mcode=0; uint32_t mlen=0;
+    SnCommWin::ECommWinResult res = 
+        GetHeader(timeout, buf, bsize, mcode, mlen);
+    if ( (res>=kOkWithMsg) && (mcode==SnHeaderFrame::kMbedFileCode) ) {
+#ifdef DEBUG
+        printf("Got mbed file header. File length = %u\r\n",mlen);
+#endif
+        // got the header.. make the file..
+        // make the file name ALLCAPS, since LocalFileSystem will do it anyway
+        std::transform(fname.begin(), fname.end(), fname.begin(), toupper);
+        // now ensure the file name is 8.3 only -- for LocalFileSystem
+        const size_t ldlen = strlen(kLocalDir);
+        // 12 = 8.3 filename format, 1 for / and 1 for \0
+        const uint32_t fbs = ldlen+1+12+1;
+        char fnb[fbs];
+        char* fb = fnb;
+        memcpy(fb, kLocalDir, ldlen); fb+=ldlen;        // /local
+        memset(fb, '/', 1); fb+=1;                      //       /
+        strncpy(fb, fname.c_str(), 8); fb+=8;           //        FILENAME
+        *fb = '.'; ++fb;                                //                .
+        strncpy(fb, fname.c_str()+fname.size()-3, 3);   //                 EXT
+        // all that just for the file name!
+        FILE* lf  = fopen(fnb,"wb");
+#ifdef DEBUG
+        printf("tried to open file [%s]. lf=%p\r\n",fnb,(void*)lf);
+#endif
+        // get all the data and dump it into the file
+        int b = 0, toget = 0;
+        while ( mlen>b ) {
+            if (IsTimedOut(timeout)) {
+#ifdef DEBUG
+                printf("timeout while getting file\r\n");
+#endif
+                res = kFailTimeout;
+                break;
+            }
+            toget = mlen - b;
+            if (toget>bsize) {
+                toget = bsize;
+            }
+            const int got = ReceiveAll(buf, toget, timeout);
+            if (lf!=NULL) {
+                SnBitUtils::WriteTo(lf, buf, got);
+            }
+            b += got;
+        }
+        uint32_t crc=0;
+        if (lf!=NULL) {
+            // calculate the crc from what's actually in the file
+            fclose(lf); // to flush it
+            lf  = fopen(fnb,"rb");
+            fseek(lf, 0, SEEK_END);
+            int32_t fend = ftell(lf);
+            fseek(lf, 0, SEEK_SET);
+            char c;
+            for (int32_t i=0; i<fend; ++i) {
+                SnBitUtils::ReadFrom(lf, c);
+                if (feof(lf)==0 && ferror(lf)==0) {
+                    crc = update_crc32_xfer(crc, c);
+                } else {
+                    break;
+                }
+            }
+            fclose(lf);
+        }
+        if ( mlen!=b ) {
+            if (res > kUnexpectedRec) {
+                res = kUnexpectedRec;
+            } // otherwise it's already worse
+        } else {
+            // check that the file is ok
+            // get the checksum
+            res = GetHeader(timeout, buf, bsize, mcode, mlen);
+            if ( (res>=kOkWithMsg) && (mcode==SnHeaderFrame::kMbedFileChksCode) ) {
+                if (crc != mlen) {
+                    res = kUnexpectedRec; // important!
+                }
+            }
+        }
+        //TODO: REMOVE
+        /*
+        char dbg[250]; memset(dbg, 0, 250);
+        char* dd = buf;
+        sprintf(dbg,"lf=%s (%p), my crc=%d, b=%d, mlen=%d\r\n",fnb,(void*)lf,crc,crc,b,mlen);
+        SnHeaderFrame::WriteTo(dd, SnHeaderFrame::kStringCode, strlen(dbg));
+        strcpy(buf+SnHeaderFrame::SizeOf(),dbg);
+        SendAll(buf, SnHeaderFrame::SizeOf() + strlen(dbg), timeout);
+        */
+        ///////////
+        if (lf!=NULL) {
+            if ( res<kOkWithMsg ) {
+                // timeout, bad checksum, something else bad?
+                remove(fnb); // delete the file
+            } else {
+                // if we got a new program, remove the old ones.
+                // (schedule myself for immediate de-resolution)
+                //
+                // first just count how many we would save
+                const uint16_t nSavedBins = LoopLocalDirBinFiles(false, fname);
+                if (nSavedBins==1) {
+                    // ok. new program will be the only one. remove the others
+                    // hope the new program works!
+                    LoopLocalDirBinFiles(true, fname);
+                    
+                    // goodbye cruel world, it's over. walk on by...
+                    mbed_reset();
+                }
+            }
+        }
+    }
+
+    return res;
+}
+
+int16_t SnCommWin::LoopLocalDirBinFiles(const bool doRemove,
+                                        const std::string& fname) {
+    // loop over the local directory, count the BIN files that match 'fname'
+    //
+    // fname is assumed to be all caps already!
+    //
+    // if doRemove==true, will actually delete non-matching files
+    //
+    // return number of non-matching files
+    uint16_t nSavedBins = 0;
+    DIR* d( opendir(kLocalDir) );
+    struct dirent* dent;
+    if ( d!=NULL ) {
+        while ( (dent = readdir(d))!=NULL ) {
+            const size_t flen = strlen(dent->d_name);
+            const char*  dext = dent->d_name + flen - 4;
+            if ( strncmp(dext,".BIN",4)==0 || strncmp(dext,".bin",4)==0 ) {
+                // ends with .BIN
+                if (strncmp(dent->d_name, fname.c_str(), fname.size())!=0) {
+                    // some other mbed program than our new one
+                    std::string dfn(kLocalDir);
+                    dfn += "/";
+                    dfn += dent->d_name;
+                    if (doRemove) {
+                        remove(dfn.c_str());
+                    }
+                } else {
+                    ++nSavedBins;
+                }
+            } // else not an mbed program
+        }
+        closedir(d);
+    }
+    return nSavedBins;
+}
+
+SnCommWin::ECommWinResult SnCommWin::GetHeader(const uint32_t timeOut,
+                                               char* const buf,
+                                               const uint32_t bsize,
+                                               uint8_t& mcode,
+                                               uint32_t& mlen) {
+    SnCommWin::ECommWinResult res = SnCommWin::kUndefFail;
+    if (bsize>=SnHeaderFrame::kMaxSizeOf) {
+        // get header
+        const int hlen = ReceiveAll(buf, SnHeaderFrame::SizeOf(), timeOut);
+        if (hlen>0 && static_cast<uint32_t>(hlen)==SnHeaderFrame::SizeOf()) {
+            mcode=0; 
+            mlen=0;
+            const char* b = buf;
+            SnHeaderFrame::ReadFrom(b, mcode, mlen);
+#ifdef DEBUG
+            printf("mcode=%02x, mlen=%u\r\n", mcode, mlen);
+#endif
+            res = SnCommWin::kOkWithMsg;
+        }
+    }
+    return res;
+}
+
 SnCommWin::ECommWinResult SnCommWin::GetConfig(SnConfigFrame& conf,
                                                const uint32_t timeOut,
                                                char* const confBuf,
@@ -183,28 +395,30 @@
 #endif
     
     SnCommWin::ECommWinResult res = SnCommWin::kUndefFail;
-    if (bsize<SnHeaderFrame::kMaxSizeOf || bsize<SnConfigFrame::kMaxSizeOf) {
-        res = SnCommWin::kUndefFail;
-    } else {
+    if (bsize>=SnConfigFrame::kMaxSizeOf) {
         // get header
-        const int hlen = ReceiveAll(confBuf, SnHeaderFrame::SizeOf(), timeOut);
-        if (hlen>0 && static_cast<uint32_t>(hlen)==SnHeaderFrame::SizeOf()) {
-            uint8_t mcode=0; uint32_t mlen=0;
-            const char* b = confBuf;
-            SnHeaderFrame::ReadFrom(b, mcode, mlen);
-#ifdef DEBUG
-            printf("mcode=%02x, mlen=%u\r\n", mcode, mlen);
-#endif
+        uint8_t mcode=0; uint32_t mlen=0;
+        res = GetHeader(timeOut, confBuf, bsize, mcode, mlen);
+        if (res>=SnCommWin::kOkWithMsg) {
             if (mcode==SnHeaderFrame::kNoConfigCode) {
                 // no config to get
                 res = SnCommWin::kOkWthMsgNoConf;
+            } else if (mcode==SnHeaderFrame::kMbedFilenameCode) {
+                res = GetFilename(timeOut, confBuf, mlen);
+                if (res>kAllFails) {
+                    std::string fname(confBuf, mlen); // the filename
+#ifdef DEBUG
+                    printf("got filename = [%s]\r\n", fname.c_str());
+#endif  
+                    res = GetLocalFile(fname, confBuf, bsize, timeOut);
+                }
             } else if (mcode!=SnHeaderFrame::kConfigCode) {
                 res = SnCommWin::kUnexpectedRec;
             } else {
                 // get config
                 const int clen = ReceiveAll(confBuf, mlen, timeOut);
                 if (clen>0 && static_cast<uint32_t>(clen)==mlen) {
-                    b = confBuf;
+                    const char* b = confBuf;
                     conf.ReadFrom(b);
                     res = SnCommWin::kOkWithMsg;
                 } else {
@@ -212,6 +426,7 @@
                 }
             }
         } else {
+            // not a problem if we get nothing (or no config)
             res = SnCommWin::kOkNoMsg;
         }
     }
@@ -230,16 +445,20 @@
 #ifdef DEBUG
     printf("########### Send Status\r\n");
 #endif
+    uint8_t loseLSB=0, loseMSB=0;
+    uint16_t wvBase=0;
+    conf.GetPackParsFor(GetCommType(), loseLSB, loseMSB, wvBase);
     const uint32_t ssize = SnStatusFrame::SizeOf(SnStatusFrame::kIOVers, conf);
     char* b = genBuf;
     SnHeaderFrame::WriteTo(b, SnHeaderFrame::kStatusCode, ssize);
-    SnStatusFrame::WriteTo(b, GetCommType(), conf, evt, genBuf, seq, thmrate, evtrate);
+    SnStatusFrame::WriteTo(b, conf, evt, genBuf, seq, thmrate, evtrate,
+                           loseLSB, loseMSB, wvBase);
     SnHeaderFrame::WriteTo(b, SnHeaderFrame::kPowerCode, 
         pow.SizeOf(SnPowerFrame::kIOvers));
     pow.WriteTo(b);
     int msiz = b-genBuf;
 #ifdef DEBUG
-    printf("calling SendAll\r\n");
+    printf("calling SendAll (status)\r\n");
 #endif
     int mlen = SendAll(genBuf, msiz, timeout_clock);
 #ifdef DEBUG
@@ -253,16 +472,24 @@
 #ifdef DEBUG
         printf("status+power sent\r\n");
 #endif
+        // event compression parameters must be the same
+        // as those sent in the status update
         b = genBuf;
         SnHeaderFrame::WriteTo(b, SnHeaderFrame::kEventCode,
-            evt.SizeOf(SnEventFrame::kIOVers,
-                       conf.GetWvLoseLSB(), conf.GetWvLoseMSB()));
-        evt.WriteTo(b, conf.GetWvLoseLSB(), conf.GetWvLoseMSB(),
-                    conf.GetWvBaseline());
+            evt.SizeOf(SnEventFrame::kIOVers, loseLSB, loseMSB));
+        b = evt.WriteTo(b, loseLSB, loseMSB, wvBase);
+        msiz = b-genBuf;
 #ifdef DEBUG
-        printf("sending event\r\n");
-#endif        
-        return SnCommWin::kOkMsgSent;
+        printf("calling SendAll (event) %d:\r\n",msiz);
+        for (uint32_t i=0; i<msiz; i++) {
+            printf("%02X ",genBuf[i]);
+        }
+        printf("\r\n");
+#endif
+        mlen = SendAll(genBuf, msiz, timeout_clock);
+        if (mlen==msiz) {
+            return SnCommWin::kOkMsgSent;
+        }
     }
     return SnCommWin::kFailPartSent;
 }
@@ -312,11 +539,6 @@
     printf("Sending block hc %02x, len=%u\r\n",blockHeaderCode,blockSize+SnHeaderFrame::SizeOf());
 #endif
     return SendAll(genBuf, blockSize+SnHeaderFrame::SizeOf(), timeout);
-    /*
-    const int rt = SendAll(genBuf, blockSize+SnHeaderFrame::SizeOf(), timeout);
-    wait_ms(10);
-    return rt;
-    */
 }                             
 
 SnCommWin::ECommWinResult SnCommWin::SendFileContents(FILE* inf,
@@ -352,6 +574,8 @@
     // variables used when sending data
     char* b = genBuf;
     int msiz, mlen;
+    // count number of events / power readings sent
+    uint32_t evtsSent=0, powsSent=0;
     
     // first is the file header, which has no SnHeaderFrame
     msiz = SnSDUtils::SizeOfFileHeader(SnSDUtils::kIOvers);
@@ -369,9 +593,6 @@
         uint8_t hcode;
         uint32_t hlen;
         
-        // count number of events / power readings sent
-        uint32_t evtsSent=0, powsSent=0;
-
         // now just loop through file and send each block
         bool fok = true;
         while (    fok
@@ -410,44 +631,49 @@
 #ifdef DEBUG
                     printf("not ok when sending hcode=%02x\r\n",hcode);
 #endif
-                }
-            }
-        }
-        
+                } // if ok after sending block
+            } // if ok after sending block header
+        } // loop over file contents
+    } else {
+        // otherwise file size not sufficient for file header
+        // so it's either 0 or corrupted.
+        // proceed as normal even tho no contents were sent.
+        // if we're deleting files, this one will be deleted.
+        ok = true;
+    }        
 #ifdef DEBUG
-        printf("loop done. ok=%d\r\n",(int)ok);
+    printf("loop done. ok=%d\r\n",(int)ok);
 #endif
-        
-        // send number of events sent
+    
+    // send number of events sent
 #ifdef DEBUG
-        printf("sending evtsSent (%u)\r\n",evtsSent);
+    printf("sending evtsSent (%u)\r\n",evtsSent);
 #endif
-        b = genBuf;
-        SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFileNevtsCode, sizeof(uint32_t));
-        b = SnBitUtils::WriteTo(b, evtsSent);
-        msiz = b - genBuf;
-        mlen = SendAll(genBuf, msiz, timeout_clock);
-        ok &= msiz==mlen;
+    b = genBuf;
+    SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFileNevtsCode, sizeof(uint32_t));
+    b = SnBitUtils::WriteTo(b, evtsSent);
+    msiz = b - genBuf;
+    mlen = SendAll(genBuf, msiz, timeout_clock);
+    ok &= msiz==mlen;
 
 #ifdef DEBUG
-        printf("ok=%d (msiz=%d, mlen=%d)\r\n", (int)ok, msiz, mlen);
+    printf("ok=%d (msiz=%d, mlen=%d)\r\n", (int)ok, msiz, mlen);
 #endif
-        
-        // send number of power readings sent
+    
+    // send number of power readings sent
 #ifdef DEBUG
-        printf("sending powsSent (%u)\r\n",powsSent);
+    printf("sending powsSent (%u)\r\n",powsSent);
 #endif
-        b = genBuf;
-        SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFileNpwrsCode, sizeof(uint32_t));
-        b = SnBitUtils::WriteTo(b, powsSent);
-        msiz = b - genBuf;
-        mlen = SendAll(genBuf, msiz, timeout_clock);
-        ok &= msiz==mlen;
-        
+    b = genBuf;
+    SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFileNpwrsCode, sizeof(uint32_t));
+    b = SnBitUtils::WriteTo(b, powsSent);
+    msiz = b - genBuf;
+    mlen = SendAll(genBuf, msiz, timeout_clock);
+    ok &= msiz==mlen;
+    
 #ifdef DEBUG
-        printf("ok=%d (msiz=%d, mlen=%d)\r\n", (int)ok, msiz, mlen);
+    printf("ok=%d (msiz=%d, mlen=%d)\r\n", (int)ok, msiz, mlen);
 #endif
-    }
 
 
     // put file position back