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