Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
SnSDUtils.cpp
- Committer:
- uci1
- Date:
- 2013-05-23
- Revision:
- 36:87865913ae6f
- Parent:
- 31:b5bd3b189150
- Child:
- 38:9070c17536cd
File content as of revision 36:87865913ae6f:
#include "SnSDUtils.h" #include "mbed.h" #include "SDFileSystem.h" #include "FATDirHandle.h" #include <string.h> #include <string> #include "SnConfigFrame.h" #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}; FILE* SnSDUtils::fgCurFile = 0; uint16_t SnSDUtils::fgCurSeq = 0; const uint8_t SnSDUtils::kIOvers = 3; const uint32_t SnSDUtils::kMaxSizeOfFileHdr = sizeof(uint8_t)+sizeof(uint64_t)+sizeof(uint32_t)+sizeof(uint16_t) +(sizeof(uint8_t)+(2u*sizeof(uint16_t))); // power frame v1 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) { // returns the formatted file name, or NULL if the directory is too long // and the full name cannot fit in the buffer // NOTE: this fcn uses a static buffer, and so should not be called // multiple times in the same line (that includes the calling of functions // that call this function!) // // 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 uint32_t sdlen(0); std::string subdirs( GetSubDirFor(run, seq, sdlen, true) ); const char* subdir = subdirs.c_str(); 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%05lds%05d.dat", subdir, macadr>>16, // 64 -> 48 bits run, seq); return tbuf; } else { return NULL; } } /* uint16_t SnSDUtils::GetCurSeqNum() { 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; if (ncomp<strlen(fn)) { sscanf(fn+ncomp,"s%hu.dat",&seq); } 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); #ifdef DEBUG printf("opening dir %s\r\n",dirname); #endif rd = opendir(dirname); } #ifdef DEBUG printf("returning rd=%p\r\n",(void*)rd); #endif return rd; } uint16_t SnSDUtils::GetSeqNum(const uint64_t macadr, const uint32_t run) { // count the files having expected filename format // get the run dir uint32_t rdlen(0); std::string rdnms ( GetSubDirFor(run, 0, rdlen, false) ); const char* rdnm = rdnms.c_str(); // open/make the run directory FATDirHandle* rd(dynamic_cast<FATDirHandle*>( OpenOrMakeDir(rdnm) )); struct dirent* rdent; uint16_t dseq(0), maxs(0); #ifdef DEBUG printf("starting readdir loop over %p\r\n",(void*)rd); #endif while ( (rdent = readdir(rd))!=NULL ) { #ifdef DEBUG printf("rdent = %p\r\n",(void*)rdent); #endif if ((rd->filinfo()->fattrib & AM_DIR)!=0) { #ifdef DEBUG printf("is a dir\r\n"); #endif // is a directory const int ncm = sscanf(rdent->d_name, "s%hu", &dseq); if (ncm==1) { if (dseq>maxs) { maxs = dseq; } } } #ifdef DEBUG else { printf("not a dir\r\n"); } #endif } #ifdef DEBUG printf("closing directory %p\r\n",(void*)rd); #endif closedir(rd); #ifdef DEBUG printf("Found max seq dir num %hu for run %u\r\n",run,maxs); #endif // open up the seq dir rdnms = GetSubDirFor(run, maxs, rdlen, true); rdnm = rdnms.c_str(); // 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 maxs=%hu\r\n",maxs); #endif return maxs; } FILE* SnSDUtils::OpenExistingFile(const char* name, const bool setcurrent, const bool redoDir) { FILE* f = 0; //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; strncpy(fgCurFileName, name, kFNBufSize-1); fgCurSeq = GetSeqNumFromFileName(fgCurFileName); } */ } return f; } 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); std::string subds( GetSubDirFor(run,seq,sdlen, true) ); const char* subd = subds.c_str(); #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? #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 && ffn.size()>0 ) { #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("ffn=%s\r\n",ffn.c_str()); #endif return f; } FILE* SnSDUtils::OpenNewOutputFile(const uint64_t macadr, const uint32_t run) { // opens a new file in the specified directory and writes this // this mbed's mac address as the first sizeof(uint64_t) bytes (i.e. 4 bytes) // #ifdef DEBUG printf("getting seq num\r\n"); #endif fgCurSeq = GetSeqNum(macadr, run); #ifdef DEBUG printf("getting output file name\r\n"); #endif 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", false); if (fgCurFile!=NULL && ferror(fgCurFile)==0) { #ifdef DEBUG printf("Writing file header\r\n"); #endif WriteFileHeader(fgCurFile, macadr, run, fgCurSeq); } } #ifdef DEBUG printf("fgCurFile=%p\r\n",(void*)fgCurFile); #endif 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 ( (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); } #ifdef DEBUG printf("GetDirProps: %s :: nf=%u, tb=%g\r\n", dirname, nfiles, totbytes); #endif } bool SnSDUtils::WriteHeartbeatTo(FILE* file, const uint32_t time, const uint32_t num) { const SnCommWin::ECommWinResult r1 = SnHeaderFrame::WriteTo(file, SnHeaderFrame::kHeartbeatCode, SnHeartbeatFrame::SizeOf(SnHeartbeatFrame::kIOVers)); const SnCommWin::ECommWinResult r2 = SnHeartbeatFrame::WriteTo(file, time, num); return ((r1==SnCommWin::kOkMsgSent) && (r2==SnCommWin::kOkMsgSent)); } bool SnSDUtils::WriteEventTo(FILE* efile, char* const evtBuf, const SnEventFrame& evt, const SnConfigFrame& conf) { // write event to SD card uint8_t sLoseLSB=0, sLoseMSB=0; uint16_t sWvBase=0; conf.GetPackParsFor(SnConfigFrame::kSDcard, sLoseLSB, sLoseMSB, sWvBase); SnHeaderFrame::WriteTo(efile, SnHeaderFrame::kEventCode, evt.SizeOf(SnEventFrame::kIOVers, sLoseLSB, sLoseMSB)); const bool ret = evt.WriteTo(efile, evtBuf, sLoseLSB, sLoseMSB, sWvBase); fflush(efile); return ret; } bool SnSDUtils::WriteConfig(FILE* efile, const SnConfigFrame& conf) { SnHeaderFrame::WriteTo(efile, SnHeaderFrame::kConfigCode, conf.SizeOf(SnConfigFrame::kIOVers)); conf.WriteTo(efile); return true; } void SnSDUtils::DeleteFile(FILE*& f, const char* fname) { #ifdef DEBUG printf("try to delete %s at %p\r\n",fname,f); #endif if (f!=0) { fclose(f); f=0; } std::string fn(""); if (GetFullFilename(fname, fn)) { #ifdef DEBUG printf("calling remove [%s]\r\n",fn.c_str()); #endif remove(fn.c_str()); } } void SnSDUtils::DeleteFilesOfRun(const uint32_t run) { #ifdef DEBUG printf("deleteing files of run %lu\r\n",run); #endif uint32_t rdlen(0); std::string rdnm( GetSubDirFor(run, 0, rdlen, false) ); DeleteAllFiles(rdnm.c_str()); } void SnSDUtils::DeleteAllFiles(const char* dirname) { #ifdef DEBUG printf("deleting ALL files in %s\r\n",dirname); #endif DIR* d; struct dirent* dent; if ( (d = opendir( dirname ))!=NULL ) { FATDirHandle* dir = dynamic_cast<FATDirHandle*>(d); while ( (dent = readdir(d))!=NULL ) { Watchdog::kick(); // don't reset if ( (dir->filinfo()->fattrib & AM_DIR)!=0 ) { // a subdirectory std::string dnm(dirname); dnm += "/"; dnm += dent->d_name; // delete all the files in this new subdir #ifdef DEBUG printf("call DeleteAllFiles(%s)\r\n",dnm.c_str()); #endif DeleteAllFiles(dnm.c_str()); } else if (strncmp(dent->d_name, "SnEvts", 6)==0) { // a data file (delete it) const bool isCurFile = (strcmp(dent->d_name, GetCurFileName())==0); if (isCurFile==false) { // don't delete the current file FILE* f(0); // dummy DeleteFile(f, dent->d_name); } } } // loop over stuff in this dir closedir(d); DeleteDirIfEmpty(dirname); } } void SnSDUtils::DeleteDirIfEmpty(const char* dirname) { #ifdef DEBUG printf("DeleteDirIfEmpty(%s)\r\n",dirname); #endif DIR* d; struct dirent* dent; 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); } } } SnCommWin::ECommWinResult SnSDUtils::SendAllFiles(SnCommWin* comm, const uint32_t timeout, char* const buf, const uint32_t bsize, const SnConfigFrame& curConf, SnEventFrame& evt, SnPowerFrame& pow, const uint32_t handshakeTimeout, const char* dirname) { SnCommWin::ECommWinResult rs = SnCommWin::kOkMsgSent; DIR* d; struct dirent* dent; if ( (d = opendir( dirname ))!=NULL ) { FATDirHandle* dir = dynamic_cast<FATDirHandle*>(d); while ( (dent = readdir(d))!=NULL ) { Watchdog::kick(); // don't reset SnCommWin::ECommWinResult res = rs; 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 res = 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 { 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; res = comm->SendData(f, dent->d_name, curConf, evt, pow, buf, bsize, 0, timeout, handshakeTimeout, &hndres); #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); } } if ((res<rs) || (res==SnCommWin::kOkStopComm)) { rs = res; } // don't necessarily stop if rs is bad. don't want one bad file to // prevent sending the others if (rs<=SnCommWin::kFailTimeout) { break; } else if (rs==SnCommWin::kOkStopComm) { break; } } // loop over stuff in this directory closedir(d); // see if we need to remove this directory now if (curConf.IsDeletingFiles()) { DeleteDirIfEmpty(dirname); } } return rs; }