Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
Diff: SnSDUtils.cpp
- 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;