Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
SnCommWin.cpp
- Committer:
- uci1
- Date:
- 2015-02-22
- Revision:
- 76:f8383f0292c2
- Parent:
- 65:2cb3e99ce466
- Child:
- 84:80b15993944e
File content as of revision 76:f8383f0292c2:
#include "SnCommWin.h" #include "SnHeaderFrame.h" #include "SnConfigFrame.h" #include "SnEventFrame.h" #include "SnPowerFrame.h" #include "SnStatusFrame.h" #include "SnSignalStrengthFrame.h" #include "SnSDUtils.h" #include "SnConstants.h" #include "SnCRCUtils.h" #include "SnCommPeripheral.h" #include <algorithm> #include <ctype.h> extern "C" void mbed_reset(); //#define DEBUG const char* SnCommWin::kLocalDir = "/local"; const char* SnCommWin::kDelAllConfCodeStr = "fj2io32FIJ(#jd;;.O@++/]ewavk2[49ojv"; const uint8_t SnCommWin::kDelAllConfCodeLen = 35; // length of the above string SnCommWin::SnCommWin(SnCommPeripheral* p) : fSendingInHandshake(false), fComm(p) { if (p==0) { error("SnCommWin - must have peripheral! Received 0.\r\n"); } } SnCommWin::~SnCommWin() { delete fComm; } bool SnCommWin::TrySetSysTimeUnix(const uint32_t timeout, uint32_t& prvTime, uint32_t& setTime) { return (fComm!=0) ? (fComm->TrySetSysTimeUnix(timeout,prvTime,setTime)) : false; } bool SnCommWin::Connect(const uint32_t timeout) { Watchdog::kick(); // don't reset return (fComm!=0) ? (fComm->Connect(timeout)) : false; } bool SnCommWin::CloseConn(const uint32_t timeout) { Watchdog::kick(); // don't reset return (fComm!=0) ? (fComm->CloseConn(timeout)) : false; } bool SnCommWin::PowerDown(const uint32_t timeout) { Watchdog::kick(); // don't reset return (fComm!=0) ? (fComm->PowerDown(timeout)) : false; } SnCommWin::ECommWinResult SnCommWin::SendData(SnConfigFrame& conf, SnEventFrame& evt, SnPowerFrame& pow, char* const genBuf, const uint32_t bsize, const uint32_t timeout) { #ifdef DEBUG printf("SnCommWin::SendData\r\n"); #endif Watchdog::kick(); // don't reset ECommWinResult res = kUndefFail; if ( (GetCommType() != SnConfigFrame::kIrid) || (conf.IsForcingSBDdata()) ) { // only send large amounts if we're not communicating by Iridum, // or if we are being forced to send the data over SBD if (conf.IsSendingAllFiles()) { #ifdef DEBUG printf("sending all files\r\n"); #endif res = SnSDUtils::SendAllFiles(this, timeout, genBuf, bsize, conf, evt, pow); // handshakes handled after each file, in SendDataFromFile } else { if (conf.GetCommSendData()==0) { #ifdef DEBUG printf("no data to send\r\n"); #endif res = kOkNoMsg; } else if (conf.IsSendingFilesRunSeqList()) { #ifdef DEBUG printf ("calling SendFilesInRunSeqList\r\n"); #endif res = SnSDUtils::SendFilesInRunSeqList( this, timeout, genBuf, bsize, conf, evt, pow); #ifdef DEBUG printf ("res = %d after SendFilesInRunSeqList\r\n", static_cast<int>(res)); #endif } else { // send most recent file or a few events from that file const uint32_t nev = (conf.GetCommSendData()>0) ? conf.GetCommSendData() // send N events : 0u; // send all events in last file #ifdef DEBUG printf("calling SendDataFromFile. f=%s, nev=%u\r\n", SnSDUtils::GetCurFileName(), nev); #endif uint8_t hndcode(0); uint32_t hndlen(0); res = SendDataFromFile(SnSDUtils::GetCurFile(), SnSDUtils::GetCurFileName(), conf, evt, pow, genBuf, bsize, nev, timeout, &hndcode, &hndlen); // handshake handled in SendData #ifdef DEBUG printf("after send data cur file, res=%d\r\n",(int)res); #endif } } } else { return kOkNoMsg; } return res; } SnCommWin::ECommWinResult SnCommWin::SendDataFromFile(FILE* inf, const char* infn, const SnConfigFrame& curConf, SnEventFrame& evt, SnPowerFrame& pow, char* const genBuf, const uint32_t bsize, const uint32_t nevts, const uint32_t timeout, uint8_t* hndcode, uint32_t* hndlen) { // nevts==0 ==> send all events // handshakeTimeout is never a clock time -- always a delta(t) #ifdef DEBUG printf("SnCommWin::SendDataFromFile file (%p), fn=%s\r\n",inf,infn); #endif Watchdog::kick(); // don't reset ECommWinResult res = kUndefFail; bool didDel = false; // allow up to the full window if we're not obeying timeout const uint32_t timeout_clock = curConf.IsObeyingTimeout() ? timeout : curConf.GetTimeoutTime(time(0), curConf.GetCommWinDuration()); if (inf!=0) { #ifdef DEBUG printf("sending file name %s\r\n",infn); #endif // send the file name int32_t btogo(0), ttogo(0); int32_t bsent = SendFilename(infn, genBuf, btogo, timeout_clock); if (genBuf!=0) { #ifdef DEBUG printf("calling send file contents\r\n"); #endif // send the contents bsent += SendFileContents(inf, curConf, evt, pow, genBuf, nevts, ttogo, timeout_clock); btogo += ttogo; bsent += fComm->FinishSending(timeout_clock); res = (bsent==btogo) ? SnCommWin::kOkMsgSent : SnCommWin::kFailPartSent; #ifdef DEBUG printf("res=%d (fails=%d)\r\n",(int)res,(int)kAllFails); #endif if (res>kAllFails) { #ifdef DEBUG printf("calling wait handshake\r\n"); #endif Watchdog::kick(); // don't reset // wait for handshake uint8_t hndshk(0); uint32_t hndshkLen(0); res = WaitHandshake(curConf, timeout_clock, genBuf, bsize, hndshk, &hndshkLen); if (hndcode!=0) { *hndcode = hndshk; } if (hndlen!=0) { *hndlen = hndshkLen; } #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 (SnCommWin::kOkWithMsg==res) { res = HandleHandshake( //SnSDUtils::GetCurFile(), SnSDUtils::GetCurFileName(), inf, infn, curConf, evt, pow, genBuf, bsize, timeout_clock, hndshk, hndshkLen, &nevts); didDel = (SnCommWin::kOkWthMsgDidDel==res); } } } // if genBuf!=0 } else { #ifdef DEBUG printf("inf=0!\r\n"); #endif res = kOkNoMsg; } if ( (inf!=SnSDUtils::GetCurFile()) && (didDel==false) ) { SnSDUtils::CloseOutputFile(inf); } if ( fComm->IsTimedOut(timeout_clock) ) { if ( kFailTimeout < res ) { res = kFailTimeout; } } return res; } SnCommWin::ECommWinResult SnCommWin::HandleHandshake(FILE* inf, const char* infn, const SnConfigFrame& curConf, SnEventFrame& evt, SnPowerFrame& pow, char* const genBuf, const uint32_t bsize, const uint32_t handshakeTimeout, const uint8_t hndshk, const uint32_t hndlen, const uint32_t* nevts) { SnCommWin::ECommWinResult res = SnCommWin::kUnexpectedRec; Watchdog::kick(); // don't reset if ( (hndshk==SnHeaderFrame::kHnShNoReplyCode) || (hndshk==SnHeaderFrame::kHnShOkPartlCode) ) { // nothing to do res = SnCommWin::kOkWithMsg; } else if (hndshk==SnHeaderFrame::kHnShFailNonCode) { res = SnCommWin::kFailNoneSent; } else if (hndshk==SnHeaderFrame::kHnShFailPrtCode) { res = SnCommWin::kFailPartSent; } else if (hndshk==SnHeaderFrame::kHnShOkComplCode) { // file received #ifdef DEBUG printf("HnShOkCompl: isdel=%d, isCurFil=%d (%p,%p), nevts_ptr=%p\r\n", (int)(curConf.IsDeletingFiles()), (int)(inf==SnSDUtils::GetCurFile()), (void*)inf, (void*)(SnSDUtils::GetCurFile()), (void*)(nevts)); if (nevts!=0) { printf("*nevts=%u\r\n",*nevts); } #endif if ( (curConf.IsDeletingFiles()) && (inf!=SnSDUtils::GetCurFile()) && ((nevts!=0) && (*nevts==0)) ) { // whole file was received // delete this file #ifdef DEBUG printf("deleting file %p, %s\r\n",inf,infn); #endif SnSDUtilsWhisperer::DeleteFile(inf, infn); res = SnCommWin::kOkWthMsgDidDel; } else { res = SnCommWin::kOkWithMsg; } } else if ( hndshk==SnHeaderFrame::kHnShOkStopCode ) { res = SnCommWin::kOkStopComm; } else if ( (hndshk==SnHeaderFrame::kHnShOkDelAlCode) || (hndshk==SnHeaderFrame::kHnShOkDelRnCode) ) { if ( GetDeleteAllConfirmCode(curConf, kDelAllConfCodeLen, handshakeTimeout, genBuf, bsize) ) { if (hndshk==SnHeaderFrame::kHnShOkDelAlCode) { #ifdef DEBUG printf("delete all\r\n"); #endif SnSDUtilsWhisperer::DeleteAllFiles(); } else if (hndshk==SnHeaderFrame::kHnShOkDelRnCode) { #ifdef DEBUG printf("delete run %u\r\n",hndlen); #endif SnSDUtilsWhisperer::DeleteFilesOfRun(hndlen); } res = SnCommWin::kOkStopComm; } } else if ( hndshk==SnHeaderFrame::kHnShOkClRSLCode ) { #ifdef DEBUG printf("clear run seq list requested\r\n"); #endif SnSDUtils::ClearRunSeqList(curConf.IsSendingFilesRunSeqList()); } else if ( hndshk==SnHeaderFrame::kHnShOkReqRnCode ) { #ifdef DEBUG printf("run %u requested\r\n",hndlen); #endif if (fSendingInHandshake==false) { // prevent another SendAllOfRun handshake request until we're done // (allowing it could lead to a stack overflow) fSendingInHandshake = true; SnSDUtils::SendAllOfRun(this, handshakeTimeout, genBuf, bsize, curConf, evt, pow, hndlen); fSendingInHandshake = false; res = SnCommWin::kOkStopComm; } } else if ( hndshk==SnHeaderFrame::kHnShOkRqPtRnCode ) { #ifdef DEBUG printf("part of run %u requested\r\n",hndlen); #endif // need the seq limits -- another handshake message SendHndshkReq(genBuf, handshakeTimeout); uint8_t shndshk(0); uint32_t shndshkLen(0); res = WaitHandshake(curConf, handshakeTimeout, genBuf, bsize, shndshk, &shndshkLen); if (SnCommWin::kOkWithMsg==res) { if ( shndshk==SnHeaderFrame::kHnShOkRqPtSqCode ) { // ok got the min/max seq's as expected const uint16_t minseq = GetMinSeqFrom(shndshkLen); const uint16_t maxseq = GetMaxSeqFrom(shndshkLen); #ifdef DEBUG printf("[minseq=%hu, maxseq=%hu]\r\n",minseq,maxseq); #endif if (fSendingInHandshake==false) { // prevent another SendAllOfRun handshake request // until we're done // (allowing it could lead to a stack overflow) fSendingInHandshake = true; SnSDUtils::SendPartOfRun(this, handshakeTimeout, genBuf, bsize, curConf, evt, pow, hndlen, // the run num minseq, maxseq); fSendingInHandshake = false; } } } res = SnCommWin::kOkStopComm; } return res; } bool SnCommWin::GetDeleteAllConfirmCode(const SnConfigFrame& conf, const uint32_t length, const uint32_t timeout, char* const buf, const uint32_t bsize) { bool ret = false; #ifdef DEBUG printf("GetDeleteAllConfirmCode, timeout=%u\r\n",timeout); #endif Watchdog::kick(); // don't reset // better pull all the bytes no matter the buffer size const uint32_t ll = (bsize<length) ? bsize : length; int mlen = 0; while ( mlen<length ) { mlen += fComm->ReceiveAll(buf, ll, timeout); if (fComm->IsTimedOut(timeout)) { break; } } Watchdog::kick(); // don't reset if (mlen==length) { const char* b = buf; const char* c = kDelAllConfCodeStr; bool match = true; for (uint8_t i=0; (i<kDelAllConfCodeLen) && match; ++i, ++b, ++c) { match = ((*b)==(*c)); } ret = match; } return ret; } SnCommWin::ECommWinResult SnCommWin::WaitHandshake(const SnConfigFrame& conf, const uint32_t timeout, char* const buf, const uint32_t bsize, uint8_t& hndShkCode, uint32_t* hndShkLen) { #ifdef DEBUG printf("WaitHandshake, timeout=%u\r\n",timeout); #endif Watchdog::kick(); // don't reset const int mlen = fComm->ReceiveAll(buf, SnHeaderFrame::SizeOf(), timeout); if (mlen>0 && static_cast<uint32_t>(mlen) == SnHeaderFrame::SizeOf()) { uint32_t msgLen=0; const char* b = buf; SnHeaderFrame::ReadFrom(b, hndShkCode, msgLen); #ifdef DEBUG printf("got handshake code=%02x, len=%u\r\n",hndShkCode,msgLen); #endif if ((hndShkCode & SnHeaderFrame::kHndShkBits)!=0) { if (hndShkLen!=0) { *hndShkLen = msgLen; } return SnCommWin::kOkWithMsg; } else { // TODO: somehow handle unexpected message? return SnCommWin::kUnexpectedRec; } } 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 Watchdog::kick(); // don't reset const int mlen = fComm->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 Watchdog::kick(); // don't reset // get the header for the file uint8_t mcode=0; uint32_t mlen=0; SnCommWin::ECommWinResult res = GetHeader(timeout, buf, bsize, mcode, mlen); #ifdef DEBUG printf("Got header code %x, len %u\r\n",mcode,mlen); #endif 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 SnCommPeripheral::CapitalizeInPlace(fname.begin(), fname.end()); // 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]; memset(fnb, 0, sizeof(char)*fbs); Watchdog::kick(); // don't reset // find the extension const size_t xdot = fname.rfind('.'); if (xdot!=string::npos && (fname.size()==(4+xdot))) { const size_t fnpl = (xdot>8) ? 8 : xdot; char* fb = fnb; memcpy(fb, kLocalDir, ldlen); fb+=ldlen; // /local *fb = '/'; ++fb; // / strncpy(fb, fname.c_str(), fnpl); fb+=fnpl; // FILENAME *fb = '.'; ++fb; // . strncpy(fb, fname.c_str()+xdot+1, 3); // EXT Watchdog::kick(); // don't reset // 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 (fComm->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 = fComm->ReceiveAll(buf, toget, timeout); if (lf!=NULL) { #ifdef DEBUG printf("writing %d bytes to file\r\n", got); #endif Watchdog::kick(); // don't reset SnBitUtils::WriteTo(lf, buf, got); } b += got; } // file data receive loop Watchdog::kick(); // don't reset uint32_t crc=0; if (lf!=NULL) { // calculate the crc from what's actually in the file fclose(lf); // to flush it #ifdef DEBUG printf("fopen: %s\r\n",fnb); #endif lf = fopen(fnb,"rb"); if (lf!=0) { 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) { Watchdog::kick(); // don't reset SnBitUtils::ReadFrom(lf, c); if (feof(lf)==0 && ferror(lf)==0) { crc = SnCRCUtils::update_crc32_xfer(crc, c); } else { break; } } fclose(lf); } #ifdef DEBUG printf("closed file. crc = %u\r\n", crc); #endif } // if output file not 0 #ifdef DEBUG printf("mlen=%u, b=%d, eq=%s\r\n",mlen,b, (mlen==b)?"true":"false"); #endif if ( mlen!=b ) { if (res > kUnexpectedRec) { res = kUnexpectedRec; } // otherwise it's already worse } else { Watchdog::kick(); // don't reset // check that the file is ok // get the checksum res = GetHeader(timeout, buf, bsize, mcode, mlen); if ( (res>=kOkWithMsg) && (mcode==SnHeaderFrame::kMbedFileChksCode) ) { #ifdef DEBUG printf("received chksum=%u, crc=%u, eq=%s\r\n", mlen,crc,(crc==mlen)?"true":"false"); #endif if (crc != mlen) { #ifdef DEBUG printf("checksums differ! unexpected.\r\n"); #endif res = kUnexpectedRec; // important! } } } // end get remote file checksum if (lf!=NULL) { if ( res<kOkWithMsg ) { // timeout, bad checksum, something else bad? #ifdef DEBUG printf("removing %s\r\n",fnb); #endif 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); #ifdef DEBUG printf("nSavedBins=%hu",nSavedBins); #endif if (nSavedBins==1) { // ok. new program will be the only one. remove the others // hope the new program works! LoopLocalDirBinFiles(true, fname); #ifdef DEBUG printf("rebooting\r\n"); #endif // goodbye cruel world, it's over. walk on by... mbed_reset(); } } // end check new program block } // if output file not 0 } else { // filename mangled. either doesn't contain a '.' // or the extension is longer than 3 letters #ifdef DEBUG printf("filname mangled. (%s) size=%u, xdot=%u", fname.c_str(), fname.size(), xdot); #endif res = SnCommWin::kUnexpectedRec; } } // if header ok 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 Watchdog::kick(); // don't reset uint16_t nSavedBins = 0; DIR* d( opendir(kLocalDir) ); struct dirent* dent; if ( d!=NULL ) { while ( (dent = readdir(d))!=NULL ) { Watchdog::kick(); // don't reset 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; Watchdog::kick(); // don't reset if (bsize>=SnHeaderFrame::kMaxSizeOf) { // get header const int hlen = fComm->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, const uint32_t bsize) { // confBuf assumed to alread be of allocated size #ifdef DEBUG printf("GetConfig, to=%u\r\n",timeOut); #endif Watchdog::kick(); // don't reset SnCommWin::ECommWinResult res = SnCommWin::kUndefFail; if (bsize>=SnConfigFrame::kMaxSizeOf) { // get header 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 fnameb(confBuf, mlen); // the filename std::string fname(fnameb.c_str()); // mlen may include the \0 which would be counted in size() #ifdef DEBUG printf("got filename = [%s] (%u)\r\n", fname.c_str(), fname.size()); #endif res = GetLocalFile(fname, confBuf, bsize, timeOut); } } else if (mcode!=SnHeaderFrame::kConfigCode) { res = SnCommWin::kUnexpectedRec; } else { // get config const int clen = fComm->ReceiveAll(confBuf, mlen, timeOut); if (clen>0 && static_cast<uint32_t>(clen)==mlen) { const uint8_t Rv = SnConfigFrame::PeekIOversion(confBuf); if (SnConfigFrame::IsIOversionOk(Rv)) { const char* b = confBuf; conf.ReadFrom(b); res = SnCommWin::kOkWithMsg; } else { res = SnCommWin::kUnexpectedRec; char s[256]; sprintf(s,"Cannot accept config version [%hhu]. " "Expect [%hhu].",Rv,SnConfigFrame::kIOVers); SendString(s, timeOut); } } else { res = SnCommWin::kUnexpectedRec; } } } else { // not a problem if we get nothing (or no config) res = SnCommWin::kOkNoMsg; } } return res; } int32_t SnCommWin::SendHndshkReq(char* const genBuf, const uint32_t timeout_clock) { // send a request demanding a handshake // as we will be waiting for a response after this, // FinishSending is also called Watchdog::kick(); // don't reset char* b = genBuf; SnHeaderFrame::WriteTo(b, SnHeaderFrame::kHnShDemandCode, 0); const uint32_t bytesToBeSent = b-genBuf; const int32_t mlen = fComm->SendAll(genBuf, bytesToBeSent, timeout_clock); const int32_t flen = fComm->FinishSending(timeout_clock); #ifdef DEBUG printf("SendHndshkReq: time = %u, timeout = %u, mlen=%d, flen=%d\r\n", time(0), timeout_clock, mlen, flen); #endif return mlen+flen; } SnCommWin::ECommWinResult SnCommWin::SendSignalStrength(char* const genBuf, SnSignalStrengthFrame& sigstr, const uint32_t timeout_clock) { // try to get the signal strength and send it if possible Watchdog::kick(); // don't reset float ss; if ( fComm->CheckSignalStrength(timeout_clock, ss) ) { char* b = genBuf; SnHeaderFrame::WriteTo(b, SnHeaderFrame::kSignalStrCode, sigstr.SizeOf()); sigstr.SetSigStr(ss, time(0)); sigstr.SetCommType( static_cast<uint8_t>(GetCommType()) ); sigstr.WriteTo(b); const uint32_t bytesToBeSent = b - genBuf; const int32_t mlen = fComm->SendAll(genBuf, bytesToBeSent, timeout_clock); const int32_t flen = fComm->FinishSending(timeout_clock); if (bytesToBeSent==(mlen+flen)) { return SnCommWin::kOkMsgSent; } else { return SnCommWin::kFailPartSent; } } return SnCommWin::kFailNoneSent; } SnCommWin::ECommWinResult SnCommWin::SendStatus(const SnConfigFrame& conf, const SnEventFrame& evt, const SnPowerFrame& pow, const uint16_t seq, const float thmrate, const float evtrate, const uint32_t powerOnTime, const SnTempFrame& temper, char* const genBuf, const uint32_t timeout_clock) { // TODO: check if connected? #ifdef DEBUG printf("########### Send Status\r\n"); #endif Watchdog::kick(); // don't reset 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, conf, evt, genBuf, seq, thmrate, evtrate, powerOnTime, temper, loseLSB, loseMSB, wvBase); SnHeaderFrame::WriteTo(b, SnHeaderFrame::kPowerCode, pow.SizeOf(SnPowerFrame::kIOvers)); pow.WriteTo(b); int32_t msiz = b-genBuf; #ifdef DEBUG printf("calling SendAll (status)\r\n"); #endif int32_t mlen = fComm->SendAll(genBuf, msiz, timeout_clock); #ifdef DEBUG printf("SendAll returned %d\r\n",mlen); #endif mlen += fComm->FinishSending(timeout_clock); #ifdef DEBUG printf("mlen=%d after FinishSending. msiz=%d\r\n",mlen,msiz); printf("status frame:\r\n"); for (uint32_t i=0; i<msiz; i++) { printf("%02X ",genBuf[i]); } printf("\r\n"); #endif if (mlen==msiz) { #ifdef DEBUG printf("status+power sent\r\n"); #endif Watchdog::kick(); // don't reset // 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, loseLSB, loseMSB)); b = evt.WriteTo(b, loseLSB, loseMSB, wvBase); msiz = b-genBuf; #ifdef DEBUG 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 = fComm->SendAll(genBuf, msiz, timeout_clock); mlen += fComm->FinishSending(timeout_clock); if (mlen==msiz) { return SnCommWin::kOkMsgSent; } } return SnCommWin::kFailPartSent; } SnCommWin::ECommWinResult SnCommWin::SendString(const char* str, const uint32_t timeout) { #ifdef DEBUG printf("SnCommWin::SendString %s\r\n",str); #endif Watchdog::kick(); // don't reset const bool ok = fComm->SendString(str, timeout); return (ok) ? SnCommWin::kOkMsgSent : SnCommWin::kFailPartSent; } int32_t SnCommWin::SendFilename(const char* inf, char* const genBuf, int32_t& bytesToBeSent, const uint32_t timeout_clock) { #ifdef DEBUG printf("SnCommWin::SendFilename %s\r\n",inf); #endif Watchdog::kick(); // don't reset // remove the directory const char* fn = strrchr(inf, '/'); if (fn==0) { // no directory fn = inf; } else if (fn!=inf) { ++fn; // move past the '/' if it was found } #ifdef DEBUG printf("send %s\r\n",fn); #endif const size_t flen = strlen(fn); char* b = genBuf; SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFilenameCode, flen); b = SnBitUtils::WriteTo(b, fn, flen); bytesToBeSent = b-genBuf; const int32_t mlen = fComm->SendAll(genBuf, bytesToBeSent, timeout_clock); #ifdef DEBUG printf("time = %u, timeout = %u\r\n",time(0), timeout_clock); #endif return mlen; } int32_t SnCommWin::SendFileBlock(FILE* inf, const uint8_t blockHeaderCode, const uint32_t blockSize, char* const genBuf, int32_t& bytesToSend, const uint32_t timeout) { // sends the block from the file. does not check if the file has sufficient bytes // this should be done before calling this function // (where the number of bytes in the file can be cached) // // bytesToSend will be set to the total bytes that should be delivered eventually // the number of bytes actually shipped out by SendAll is returned Watchdog::kick(); // don't reset char* b = genBuf; SnHeaderFrame::WriteTo(b, blockHeaderCode, blockSize); SnBitUtils::ReadFrom(inf, b, blockSize); #ifdef DEBUG printf("Sending block hc %02x, len=%u\r\n",blockHeaderCode,blockSize+SnHeaderFrame::SizeOf()); #endif bytesToSend = blockSize+SnHeaderFrame::SizeOf(); return fComm->SendAll(genBuf, bytesToSend, timeout); } int32_t SnCommWin::SendFileContents(FILE* inf, const SnConfigFrame& curConf, SnEventFrame& evt, SnPowerFrame& pow, char* const genBuf, uint32_t nevts, int32_t& bytesToBeSent, const uint32_t timeout_clock) { // firstEvt==0 ==> start at beginning // nevts==0 ==> all events // // bytesToSend will be set to the total bytes that should be delivered eventually // the number of bytes actually shipped out by SendAll is returned #ifdef DEBUG printf("SendFileContents (byte streaming)\r\n"); #endif Watchdog::kick(); // don't reset // store position in file so we can go back to it afterwards // this is probably not necessary, because if this file is open // in write-only mode, we're screwed.. const int fpos = ftell(inf); if (fpos>0) { fseek(inf, 0, SEEK_SET); } // how many bytes? fseek(inf, 0, SEEK_END); // go to end const int fend = ftell(inf); fseek(inf, 0, SEEK_SET); // go to start #ifdef DEBUG printf("fend=%d\r\n",fend); printf("fpos=%d\r\n",fpos); #endif // variables used when sending data char* b = genBuf; int32_t msiz(0), mlen(0), mtogo(0), tsent(0); // count number of events / power readings sent uint32_t evtsSent=0, powsSent=0, crc=0; Watchdog::kick(); // don't reset // first is the file header, which has no SnHeaderFrame msiz = SnSDUtils::SizeOfFileHeader(SnSDUtils::kIOvers); bool ok = (ftell(inf)+msiz)<=fend; if (ok) { mlen = SendFileBlock(inf, SnHeaderFrame::kFileHeadrCode, msiz, genBuf, mtogo, timeout_clock); //ok &= (msiz+SnHeaderFrame::SizeOf())==mlen; bytesToBeSent += mtogo; tsent += mlen; #ifdef DEBUG printf("sent file header. ok=%d\r\n",(int)ok); #endif Watchdog::kick(); // don't reset // calc crc w/o the header block of the file header, as // this does not get stored in the file crc = SnCRCUtils::GetUpdatedCRC32for(crc, genBuf+SnHeaderFrame::SizeOf(), mtogo-SnHeaderFrame::SizeOf()); // the header info for each block uint8_t hcode(0); uint32_t hlen(0); // now just loop through file and send each block bool fok = true; while ( fok && (feof(inf)==0) && (ferror(inf)==0) && ((ftell(inf)+SnHeaderFrame::SizeOf())<=fend) ) { Watchdog::kick(); // don't reset // read the header for the block SnSDUtils::ReadBlockHeader(inf, hcode, hlen); fok &= (ftell(inf)+hlen)<=fend; #ifdef DEBUG printf("new block: hc=%02x, hl=%u, ftell=%d, fend=%d, " "ok=%d, fok=%d\r\n", hcode, hlen, ftell(inf), fend, (int)ok, (int)fok); #endif if (fok) { // send the block // TODO: repack events? mlen = SendFileBlock(inf, hcode, hlen, genBuf, mtogo, timeout_clock); bytesToBeSent += mtogo; tsent += mlen; crc = SnCRCUtils::GetUpdatedCRC32for(crc, genBuf, mtogo); if (hcode==SnHeaderFrame::kEventCode) { ++evtsSent; if (nevts>0) { if (evtsSent>=nevts) { #ifdef DEBUG printf("sent %u events. stop\r\n",evtsSent); #endif break; } } } else if (hcode==SnHeaderFrame::kPowerCode) { ++powsSent; } } // otherwise file size not sufficient for this block } // 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); #endif Watchdog::kick(); // don't reset // send the crc #ifdef DEBUG printf("sending crc (%u)\r\n",crc); #endif b = genBuf; SnHeaderFrame::WriteTo(b, SnHeaderFrame::kMbedFileChksCode, sizeof(uint32_t)); b = SnBitUtils::WriteTo(b, crc); msiz = b - genBuf; mlen = fComm->SendAll(genBuf, msiz, timeout_clock); bytesToBeSent += msiz; tsent += mlen; #ifdef DEBUG printf("(msiz=%d, mlen=%d)\r\n", msiz, mlen); #endif Watchdog::kick(); // don't reset // send number of events sent #ifdef DEBUG 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 = fComm->SendAll(genBuf, msiz, timeout_clock); bytesToBeSent += msiz; tsent += mlen; #ifdef DEBUG printf("(msiz=%d, mlen=%d)\r\n", msiz, mlen); #endif Watchdog::kick(); // don't reset // send number of power readings sent #ifdef DEBUG 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 = fComm->SendAll(genBuf, msiz, timeout_clock); bytesToBeSent += msiz; tsent += mlen; #ifdef DEBUG printf("(msiz=%d, mlen=%d)\r\n", msiz, mlen); #endif // put file position back fseek(inf, fpos, SEEK_SET); #ifdef DEBUG printf("end contents: ok=%d\r\n",(int)ok); #endif return tsent; //return ok ? SnCommWin::kOkMsgSent : SnCommWin::kFailPartSent; }