Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Revision:
25:57b2627fe756
Parent:
22:f957c4f840ad
Child:
27:efc4d654b139
--- a/SnSDUtils.cpp	Tue Oct 23 20:58:29 2012 +0000
+++ b/SnSDUtils.cpp	Tue Oct 30 05:23:57 2012 +0000
@@ -10,8 +10,12 @@
 #include "SnEventFrame.h"
 #include "SnHeartbeatFrame.h"
 
+#include "Watchdog.h"
+
 //#define DEBUG
 
+#define SUBDIRSEQ 100  // make a new subdir every X sequences
+
 const char* const SnSDUtils::kSDdir     = "/sd";
 const char* const SnSDUtils::kSDsubDir  = "/sd/data";
 char              SnSDUtils::fgCurFileName[kFNBufSize]={0};
@@ -24,6 +28,18 @@
 
 static const uint16_t __kMaxUShort = ~0;
 
+const char* SnSDUtils::GetSubDirFor(const uint32_t run, const uint16_t seq,
+                                    uint32_t& slen, const bool useSeq) {
+    // returns a STATIC string!
+    // sets slen to the length of this string (same as strlen)
+    static char* tmpsd = new char[strlen(kSDsubDir)+25];
+    slen = sprintf(tmpsd, "%s/r%05ld", kSDsubDir, run);
+    if (useSeq) {
+        slen += sprintf(tmpsd+slen, "/s%05d", (seq/SUBDIRSEQ)*SUBDIRSEQ);
+    }
+    return tmpsd;
+}
+
 const char* SnSDUtils::GetOutFileName(const uint64_t macadr,
                                       const uint32_t run,
                                       const uint16_t seq) {
@@ -35,13 +51,14 @@
     //
     // filename = SnEvtsM[6-byte hex mac adr]r[6-digit run num]s[5-digit seq num].dat
     //  35 chars      7     +    12         +1+         5     +1+     5         + 4
-    
-    if (strlen(kSDsubDir)<(kFNBufSize-37)) {
+    uint32_t sdlen(0);
+    const char* subdir = GetSubDirFor(run, seq, sdlen, true);
+    if (sdlen<(kFNBufSize-37)) {
         static char tbuf[kFNBufSize];
         memset(tbuf, 0, sizeof(char)*kFNBufSize);
         // if file name format changes, GetSeqNum must be changed too
-        sprintf(tbuf, "%s/SnEvtsM%012llXr%05ds%05d.dat",
-            kSDsubDir,
+        sprintf(tbuf, "%s/SnEvtsM%012llXr%05lds%05d.dat",
+            subdir,
             macadr>>16, // 64 -> 48 bits
             run, seq);
         return tbuf;
@@ -54,6 +71,26 @@
     return GetSeqNumFromFileName(fgCurFileName);
 }
 */
+
+bool SnSDUtils::GetRunSeqFromFilename(const char* fn,
+                                      uint32_t& run,
+                                      uint16_t& seq) {
+    bool ret = false;
+    const int32_t ncomp = strrchr(fn, 'r') - fn;
+#ifdef DEBUG
+    printf("fn=%s, ncomp=%d\r\n",fn,ncomp);
+#endif
+    if ((ncomp<strlen(fn)) && (ncomp>0)) {
+        if (sscanf(fn+ncomp,"r%lus%hu.dat",&run,&seq)==2) {
+#ifdef DEBUG
+            printf("run=%u, seq=%hu\r\n",run,seq);
+#endif
+            ret = true;
+        }
+    }
+    return ret;
+}
+/*
 uint16_t SnSDUtils::GetSeqNumFromFileName(const char* fn) {
     uint16_t seq=0;
     const uint32_t ncomp = strrchr(fn, 's') - fn;
@@ -62,61 +99,105 @@
     }
     return seq;
 }
+*/
+DIR* SnSDUtils::OpenOrMakeDir(const char* dirname) {
+#ifdef DEBUG
+    printf("open dir %s\r\n",dirname);
+#endif
+    DIR* rd( opendir(dirname) );
+    if (rd==NULL) {
+        // try making the directory
+#ifdef DEBUG
+        printf("making dir %s\r\n",dirname);
+#endif
+        mkdir(dirname, 0777);
+        rd = opendir(dirname);
+    }
+    return rd;
+}
 
 uint16_t SnSDUtils::GetSeqNum(const uint64_t macadr,
                               const uint32_t run) {
     // count the files having expected filename format
     
-    // fn points to a static buffer
-    const char* fn = GetOutFileName(macadr, run, 0)
-        + strlen(kSDsubDir) + 1; // take out dir and '/'s
-    
-    DIR* d( opendir(kSDsubDir) );
-    if (d==NULL) {
-        // try making the directory
-        mkdir(kSDsubDir, 0777);
-        d = opendir( kSDsubDir );
-    }
-    struct dirent* dent;
-    
-    uint16_t seq=0, newseq=0;
-    if ( d!=NULL ) {
-        // don't compare seq#. don't use num of chars in case seq is >999
-        const uint32_t ncomp = strrchr(fn, 's') - fn;
-        while ( (dent = readdir(d))!=NULL ) {
-            if (strncmp(dent->d_name, fn, ncomp)==0) {
-                // allow for deleted files to make gaps.
-                // search for highest seq number and increase that
-                sscanf((dent->d_name)+ncomp,"s%hu.dat",&seq);
-#ifdef DEBUG
-                printf("dn=%s, seq=%hu, __kMaxUShort=%hu\r\n",
-                    dent->d_name, seq, __kMaxUShort);
-#endif
-                if (seq==__kMaxUShort) {
-                    newseq = seq;
-                    break;
-                }
-                if (seq>=newseq) {
-                    newseq=seq+1;
-                }
-                if (newseq==__kMaxUShort) {
-                    break;
+    // get the run dir
+    uint32_t rdlen(0);
+    const char* rdnm = GetSubDirFor(run, 0, rdlen, false);
+    // open/make the run directory
+    FATDirHandle* rd(dynamic_cast<FATDirHandle*>( OpenOrMakeDir(rdnm) ));
+    struct dirent* rdent;
+    uint16_t dseq(0), maxs(0);
+    while ( (rdent = readdir(rd))!=NULL ) {
+        if ((rd->filinfo()->fattrib & AM_DIR)!=0) {
+            // is a directory
+            const int ncm = sscanf(rdent->d_name, "s%hu", &dseq);
+            if (ncm==1) {
+                if (dseq>maxs) {
+                    maxs = dseq;
                 }
             }
         }
-        closedir(d);
     }
+    closedir(rd);
+#ifdef DEBUG
+    printf("Found max seq dir num %hu for run %u\r\n",run,maxs);
+#endif
+    // open up the seq dir
+    rdnm = GetSubDirFor(run, maxs, rdlen, true);
+    // runXseq0 filename (fn points to a static buffer)
+    const char* fn = GetOutFileName(macadr, run, maxs)
+        + rdlen + 1; // take out dir and '/'s
+    // don't compare seq#. don't use num of chars in case seq is >999
+    const int32_t ncomp = strrchr(fn, 's') - fn;
+    // open (or make) the run/seq dir
+    rd = dynamic_cast<FATDirHandle*>( OpenOrMakeDir(rdnm) );
+    // get the new sequence number (ok if it overflows this seq "bin")
+    maxs=0;
+    while ( (rdent = readdir(rd))!=NULL ) {
+        Watchdog::kick(); // don't reset
+        if ((rd->filinfo()->fattrib & AM_DIR)==0) {
+            // is a file.
+            // don't just count files, in case one seq was
+            // transferred and erased in the middle of a run
+            if (strncmp(rdent->d_name, fn, ncomp)==0) {
+                // allow for deleted files to make gaps.
+                // search for highest seq number and increase that
+                if (sscanf((rdent->d_name)+ncomp,"s%hu.dat",&dseq)==1) {
+#ifdef DEBUG
+                    printf("dn=%s, seq=%hu, __kMaxUShort=%hu\r\n",
+                        rdent->d_name, dseq, __kMaxUShort);
+#endif
+                    if (dseq==__kMaxUShort) {
+                        maxs = dseq;
+                        break;
+                    }
+                    if (dseq>=maxs) {
+                        maxs=dseq+1;
+                    }
+                    if (maxs==__kMaxUShort) {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    closedir(rd);
 
 #ifdef DEBUG
-    printf("return newseq=%hu\r\n",newseq);
+    printf("return maxs=%hu\r\n",maxs);
 #endif
-    return newseq;
+    return maxs;
 }
 
-FILE* SnSDUtils::OpenExistingFile(const char* name, const bool setcurrent) {
+FILE* SnSDUtils::OpenExistingFile(const char* name, const bool setcurrent,
+                                  const bool redoDir) {
     FILE* f = 0;
-    if (name!=NULL) {
-        f = OpenSDFile(name, "rb");
+    //if ((name!=NULL) && ((*name)!=0) ) { // simple check if filename not set
+    if (name!=NULL) { // simple check if filename not set
+#ifdef DEBUG
+        printf("opening SD file. name=[%s]\r\n",name);
+#endif
+        f = OpenSDFile(name, "rb", redoDir);
         /*
         if (setcurrent) {
             fgCurFile = f;
@@ -128,22 +209,97 @@
     return f;
 }
 
-FILE* SnSDUtils::OpenSDFile(const char* name, const char* mode) {
+bool SnSDUtils::GetFullFilename(const char* name, std::string& ffn) {
+#ifdef DEBUG
+    printf("GetFullFilename (%s)\r\n",name);
+#endif
+    bool ret = false;
+    uint32_t run(0);
+    uint16_t seq(0);
+    const char* fn = strrchr(name, '/');
+#ifdef DEBUG
+    printf("w/o / : %s\r\n",fn);
+#endif
+    if (fn!=NULL) {
+        ++fn; // remove the /
+    } else {
+        fn = name;
+    }
+    ffn = "";
+    if (GetRunSeqFromFilename(fn, run, seq)) {
+#ifdef DEBUG
+        printf("got run=%d, seq=%hu\r\n",run,seq);
+#endif
+        uint32_t sdlen(0);
+        const char* subd = GetSubDirFor(run,seq,sdlen, true);
+#ifdef DEBUG
+        printf("subd=%s\r\n",subd);
+#endif
+        ffn = subd;
+        ffn += "/";
+        ret = true;
+    }
+    ffn += fn;
+#ifdef DEBUG
+    printf("ffn=%s, ret=%d\r\n",ffn.c_str(),(int)ret);
+#endif
+    return ret;
+}
+
+FILE* SnSDUtils::OpenSDFile(const char* name, const char* mode,
+                            const bool redoDir) {
     // TODO: check if we have memory?
-    std::string fn(name);
-    if (strncmp(name, kSDsubDir, strlen(kSDsubDir))!=0) {
-        // filename lacks directory
-        fn = kSDsubDir;
-        fn += "/";
-        fn += name;
+#ifdef DEBUG
+    printf("OpenSDFile: Trying to open %s.\r\n",name);
+#endif
+    std::string ffn;
+    FILE* f = 0;
+    bool ok = true;
+#ifdef DEBUG
+    printf("redoDir=%d\r\n",(int)redoDir);
+#endif
+    if (redoDir) {
+#ifdef DEBUG
+        printf("calling GetFullFilename\r\n");
+#endif
+        ok = GetFullFilename(name, ffn);
+#ifdef DEBUG
+        printf("ffn=%s\r\n",ffn.c_str());
+#endif
+    } else {
+#ifdef DEBUG
+        printf("looking for /\r\n");
+#endif
+        // make sure the directory exists
+        const char* ld = strrchr(name, '/');
+#ifdef DEBUG
+        printf("ld=%p, ld-name = %d\r\n",ld,(int)(ld-name));
+#endif
+        if ((ld!=0) && (ld>name)) {
+            std::string dn(name, ld-name);
+            DIR* d = OpenOrMakeDir(dn.c_str());
+#ifdef DEBUG
+        printf("d=%p\r\n",d);
+#endif
+            if (d!=NULL) {
+                closedir(d);
+            }
+        }
+        // now just copy the (already-) full name
+        ffn = name;
+    }
+    if ( ok ) {
+#ifdef DEBUG
+        printf("OpenSDFile: %s, mode %s\r\n",ffn.c_str(),mode);
+#endif
+        f = fopen(ffn.c_str(), mode);
+        //setvbuf(f, 0, _IONBF, 0); // no buffering
+#ifdef DEBUG
+        printf("OpenSDFile: f=%p\r\n",(void*)f);
+#endif
     }
 #ifdef DEBUG
-    printf("OpenSDFile: %s, mode %s\r\n",fn.c_str(),mode);
-#endif
-    FILE* f = fopen(fn.c_str(), mode);
-    //setvbuf(f, 0, _IONBF, 0); // no buffering
-#ifdef DEBUG
-    printf("OpenSDFile: f=%p\r\n",(void*)f);
+    printf("ffn=%s\r\n",ffn.c_str());
 #endif
     return f;
 }
@@ -163,12 +319,15 @@
     memset(fgCurFileName, 0, sizeof(char)*kFNBufSize);
     strncpy(fgCurFileName,GetOutFileName(macadr, run, fgCurSeq),kFNBufSize-1);
     //fprintf(stderr,"cur file = %s (%hu)\n\r",fgCurFileName,fgCurSeq);
+#ifdef DEBUG
+    printf("fgCurFileName=%s\r\n",fgCurFileName);
+#endif
     fgCurFile = 0;
     if (fgCurFileName!=NULL) {
 #ifdef DEBUG
         printf("opening SD file\r\n");
 #endif
-        fgCurFile = OpenSDFile(fgCurFileName, "wb");
+        fgCurFile = OpenSDFile(fgCurFileName, "wb", false);
         if (fgCurFile!=NULL && ferror(fgCurFile)==0) {
 #ifdef DEBUG
             printf("Writing file header\r\n");
@@ -182,16 +341,53 @@
     return fgCurFile;
 }
 
+void SnSDUtils::PrintFilesInDirs(const char* dirname) {
+    DIR* d;
+    struct dirent* dent;
+    Watchdog::kick(); // don't reset
+    if ( (d = opendir( dirname ))!=NULL ) {
+        FATDirHandle* dir = dynamic_cast<FATDirHandle*>(d);
+        while ( (dent = readdir(d))!=NULL ) {
+            printf("dn=%s. datr=%02x. dir=%d\r\n",
+                dent->d_name,
+                dir->filinfo()->fattrib,
+                dir->filinfo()->fattrib & AM_DIR);
+            if ( (dir->filinfo()->fattrib & AM_DIR)!=0 ) {
+                std::string dnm(dirname);
+                dnm += "/";
+                dnm += dent->d_name;
+                PrintFilesInDirs(dnm.c_str());
+            }
+        }
+    }
+
+}
+
 void SnSDUtils::GetDirProps(const char* dirname,
                             uint32_t& nfiles,
                             float& totbytes) {
     nfiles = 0;
     totbytes = 0;
+    struct dirent* dent;
     FATDirHandle* d = dynamic_cast<FATDirHandle*>( opendir(dirname) );
     if (d!=0) {
-        while ( (readdir(d))!=NULL ) {
-            ++nfiles;
-            totbytes += d->filinfo()->fsize;
+        while ( (dent = readdir(d))!=NULL ) {
+            Watchdog::kick(); // don't reset
+            if ( (d->filinfo()->fattrib & AM_DIR)!=0 ) {
+                // a subdirectory
+                std::string dnm(dirname);
+                dnm += "/";
+                dnm += dent->d_name;
+                uint32_t sdnf;
+                float    sdtb;
+                GetDirProps(dnm.c_str(), sdnf, sdtb);
+                nfiles += sdnf;
+                totbytes += sdtb;
+             } else {
+                // a file
+                ++nfiles;
+                totbytes += d->filinfo()->fsize;
+             }
         }
         closedir(d);
     }
@@ -237,16 +433,18 @@
 }
 
 void SnSDUtils::DeleteFile(FILE*& f, const char* fname) {
+#ifdef DEBUG
+    printf("try to delete %s at %p\r\n",fname,f);
+#endif
     fclose(f);
     f=0;
-    // make sure we're trying to delete a file off the SD card
-    std::string fn(fname);
-    if (strncmp(fname,kSDsubDir,strlen(kSDsubDir))!=0) {
-        fn  = kSDsubDir;
-        fn += "/";
-        fn += fname;
+    std::string fn("");
+    if (GetFullFilename(fname, fn)) {
+#ifdef DEBUG
+        printf("calling remove [%s]\r\n",fn.c_str());
+#endif
+        remove(fn.c_str());
     }
-    remove(fn.c_str());
 }
 
 SnCommWin::ECommWinResult SnSDUtils::SendAllFiles(SnCommWin* comm,
@@ -256,49 +454,100 @@
                                                   const SnConfigFrame& curConf,
                                                   SnEventFrame& evt,
                                                   SnPowerFrame& pow,
-                                                  const uint32_t handshakeTimeout) {
+                                                  const uint32_t handshakeTimeout,
+                                                  const char* dirname) {
+
+    SnCommWin::ECommWinResult rs  = SnCommWin::kOkMsgSent;
 
     DIR* d;
     struct dirent* dent;
-    
-    SnCommWin::ECommWinResult rs  = SnCommWin::kOkMsgSent;
-    
-    if ( (d = opendir( kSDsubDir ))!=NULL ) {
-        FILE* f;
+    std::string delfile("");
+    if ( (d = opendir( dirname ))!=NULL ) {
+        FATDirHandle* dir = dynamic_cast<FATDirHandle*>(d);
         while ( (dent = readdir(d))!=NULL ) {
-            if (strncmp(dent->d_name, "SnEvts", 6)==0) {
+            Watchdog::kick(); // don't reset
+            if ( (dir->filinfo()->fattrib & AM_DIR)!=0 ) {
+                // a subdirectory
+                std::string dnm(dirname);
+                dnm += "/";
+                dnm += dent->d_name;
+                // send all the files in this new subdir
+                SendAllFiles(comm, timeout, buf, bsize, curConf, evt, pow,
+                             handshakeTimeout, dnm.c_str());
+            } else if (strncmp(dent->d_name, "SnEvts", 6)==0) {
+                // a data file (send it)
                 const bool isCurFile = 
                     (strcmp(dent->d_name, GetCurFileName())==0);
+                FILE* f(0);
                 if (isCurFile) {
                     // file must already be written out!
                     f = GetCurFile();
                 } else {
-                    f = OpenExistingFile(dent->d_name, false);
+                    std::string ffn(dirname);
+                    ffn += "/";
+                    ffn += dent->d_name;
+                    f = OpenExistingFile(ffn.c_str(), false, false);
                 }
 #ifdef DEBUG
                 printf("calling senddata: f=%p (cur %p), fn=%s\r\n",
                     f, GetCurFile(), dent->d_name);
 #endif
+                uint8_t hndres = SnHeaderFrame::kHnShFailNonCode;
                 const SnCommWin::ECommWinResult res = 
                     comm->SendData(f, dent->d_name,
                                    curConf, evt, pow, buf, bsize,
-                                   0, timeout, handshakeTimeout);
+                                   0, timeout, handshakeTimeout,
+                                   &hndres);
                 if (res<rs) {
                     rs = res;
                 }
                 // don't stop if res is bad. don't want one bad file to
                 // prevent sending the others
                 
-                // send data should close or delete the file (if appropriate)
-                // unless it's the current file
+#ifdef DEBUG
+                printf("isCurFile=%d, res=%d, deleting=%d, hndres=%02x\r\n",
+                    (int)isCurFile, (int)res, (int)(curConf.IsDeletingFiles()),
+                    hndres);
+#endif
                 if (isCurFile) {
                     // move (back) to the end of the file
                     // altho hopefully no writing will happen after this
                     fseek(fgCurFile, 0, SEEK_END);
+                } else if ( (res==SnCommWin::kOkWithMsg) // got handshake
+                         &&  curConf.IsDeletingFiles()   // want to delete
+                         && (hndres==SnHeaderFrame::kHnShOkComplCode) ) {  // whole file received
+                    // delete it
+                    DeleteFile(f, dent->d_name);
+                }
+            }
+            if (rs<=SnCommWin::kFailTimeout) {
+                break;
+            }
+        }
+        closedir(d);
+        // see if we need to remove this directory now
+        if (curConf.IsDeletingFiles()) {
+            if ( (d = opendir(dirname))!=NULL ) {
+                dent = readdir(d);
+                bool doDel = false;
+                if ( dent==NULL ) {
+                    // then this directory is empty
+                    static const size_t subdsz = strlen(kSDsubDir);
+                    // just double check that this directory is
+                    // a subdirectory of the data dir
+                    if (strlen(dirname)>subdsz) {
+                        doDel = true;
+                    }
+                } // else this dir isn't empty
+                closedir(d);
+                if (doDel) {
+#ifdef DEBUG
+                    printf("removing directory [%s]\r\n",dirname);
+#endif
+                    remove(dirname);
                 }
             }
         }
-        closedir(d);
     }
     
     return rs;