Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

SnCommWin.cpp

Committer:
uci1
Date:
2012-09-29
Revision:
18:55f1581f2ee4
Parent:
16:744ce85aede2
Child:
21:ce51bb0ba4a5

File content as of revision 18:55f1581f2ee4:

#include "SnCommWin.h"

#include "SnHeaderFrame.h"
#include "SnConfigFrame.h"
#include "SnEventFrame.h"
#include "SnPowerFrame.h"
#include "SnStatusFrame.h"
#include "SnSDUtils.h"
#include "SnConstants.h"

//#define DEBUG

uint32_t SnCommWin::GetConnectTimeout() const { return kConnectTimeout; }
uint32_t SnCommWin::GetListenTimeout() const { return kListenTimeout; }

bool SnCommWin::IsTimedOut(const uint32_t timeout_clock) const {
    if (timeout_clock==0) {
        // for not obeying timeout option
        return false;
    } else {
        const uint32_t ct = time(0);
        if ( (ct==0) ||
             (abs(static_cast<double>(timeout_clock-ct))>kSecsPerDay) ) {
            // clock problems!
            // timeout now. hope the clock problems
            // get fixed in the next comm window
            return true;
        } else {
            return (ct>timeout_clock);
        }
    }
}

SnCommWin::ECommWinResult SnCommWin::SendData(SnConfigFrame& conf,
                                              SnEventFrame& evt,
                                              SnPowerFrame& pow,
                                              char* const genBuf,
                                              const uint32_t bsize,
                                              const uint32_t timeout,
                                              const uint32_t handshakeTimeout) {
#ifdef DEBUG
    printf("SnCommWin::SendData\r\n");
#endif
    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,
                                          handshakeTimeout);
        } else {
            if (conf.GetCommSendData()==0) {
#ifdef DEBUG
                printf("no data to send\r\n");
#endif
                res = kOkNoMsg;
            } else {
                const uint32_t nev = (conf.GetCommSendData()>0) ?
                                      conf.GetCommSendData() // send N events
                                      : 0u; // send all events in last file
#ifdef DEBUG
                printf("calling SendData. f=%s, nev=%u\r\n",SnSDUtils::GetCurFileName(), nev);
#endif
                res = SendData(SnSDUtils::GetCurFile(), SnSDUtils::GetCurFileName(),
                               conf, evt, pow, genBuf, bsize, nev, timeout, handshakeTimeout);
#ifdef DEBUG
                printf("after send data cur file, res=%d\r\n",(int)res);
#endif
            }
        }
    } else {
        return kOkNoMsg;
    }
    return res;
}

SnCommWin::ECommWinResult SnCommWin::SendData(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_clock,
                                              const uint32_t handshakeTimeout) {
    // nevts==0 ==> send all events
    
#ifdef DEBUG
    printf("SnCommWin::SendData file (%p), fn=%s\r\n",inf,infn);
#endif
    ECommWinResult res = kUndefFail;
    bool didDel = false;
    if (inf!=0) {
#ifdef DEBUG
        printf("sending file name %s\r\n",infn);
#endif

        // send the file name
        res = SendFilename(infn, genBuf, timeout_clock);
        if (res>kAllFails) {
            if (genBuf!=0) {
#ifdef DEBUG
                printf("calling send file contents\r\n");
#endif

                // send the contents
                res = SendFileContents(inf, curConf, evt, pow, genBuf,
                                       nevts, timeout_clock);
#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
                    // wait for handshake
                    uint8_t hndshk=0;
                    res = WaitHandshake(handshakeTimeout, genBuf, bsize, hndshk);
                    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
                        SnSDUtilsWhisperer::DeleteFile(inf, infn);
                        didDel=true;
                    }
                }
            }
        }
    } else {
#ifdef DEBUG
        printf("inf=0!\r\n");
#endif
    }
    if ( (inf!=SnSDUtils::GetCurFile()) && (didDel==false) ) {
        SnSDUtils::CloseOutputFile(inf);
    }
    return res;
}

SnCommWin::ECommWinResult SnCommWin::WaitHandshake(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;
#ifdef DEBUG
    printf("WaitHandshake, to=%u\r\n",to);
#endif
    
    const int mlen = ReceiveAll(buf, SnHeaderFrame::SizeOf(), to);
    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) {
            return SnCommWin::kOkWithMsg;
        } else {
            // TODO: somehow handle unexpected message?
            return SnCommWin::kUnexpectedRec;
        }
    }
    return SnCommWin::kOkNoMsg;
}

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
    
    SnCommWin::ECommWinResult res = SnCommWin::kUndefFail;
    if (bsize<SnHeaderFrame::kMaxSizeOf || bsize<SnConfigFrame::kMaxSizeOf) {
        res = SnCommWin::kUndefFail;
    } else {
        // 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
            if (mcode==SnHeaderFrame::kNoConfigCode) {
                // no config to get
                res = SnCommWin::kOkWthMsgNoConf;
            } 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;
                    conf.ReadFrom(b);
                    res = SnCommWin::kOkWithMsg;
                } else {
                    res = SnCommWin::kUnexpectedRec;
                }
            }
        } else {
            res = SnCommWin::kOkNoMsg;
        }
    }
    return res;
}

SnCommWin::ECommWinResult SnCommWin::SendStatus(const SnConfigFrame& conf,
                                                const SnEventFrame& evt,
                                                const SnPowerFrame& pow,
                                                const uint16_t seq,
                                                const float thmrate,
                                                const float evtrate,
                                                char* const genBuf,
                                                const uint32_t timeout_clock) {
    // TODO: check if connected?
#ifdef DEBUG
    printf("########### Send Status\r\n");
#endif
    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);
    SnHeaderFrame::WriteTo(b, SnHeaderFrame::kPowerCode, 
        pow.SizeOf(SnPowerFrame::kIOvers));
    pow.WriteTo(b);
    int msiz = b-genBuf;
#ifdef DEBUG
    printf("calling SendAll\r\n");
#endif
    int mlen = SendAll(genBuf, msiz, timeout_clock);
#ifdef DEBUG
    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
        b = genBuf;
        SnHeaderFrame::WriteTo(b, SnHeaderFrame::kEventCode,
            evt.SizeOf(SnEventFrame::kIOVers,
                       conf.GetWvLoseLSB(), conf.GetWvLoseMSB()));
        evt.WriteTo(b, conf.GetWvLoseLSB(), conf.GetWvLoseMSB(),
                    conf.GetWvBaseline());
#ifdef DEBUG
        printf("sending event\r\n");
#endif        
        return SnCommWin::kOkMsgSent;
    }
    return SnCommWin::kFailPartSent;
}

SnCommWin::ECommWinResult SnCommWin::SendFilename(const char* inf,
                                                  char* const genBuf,
                                                  const uint32_t timeout_clock) {
#ifdef DEBUG
    printf("SnCommWin::SendFilename %s\r\n",inf);
#endif

    // 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);
    const int msiz = b-genBuf;
    const int mlen = SendAll(genBuf, msiz, timeout_clock);
#ifdef DEBUG
    printf("time = %u, timeout = %u\r\n",time(0), timeout_clock);
#endif
    return (msiz==mlen) ? SnCommWin::kOkMsgSent : SnCommWin::kFailPartSent;
}

int SnCommWin::SendFileBlock(FILE* inf, 
                             const uint8_t blockHeaderCode,
                             const uint32_t blockSize,
                             char* const genBuf,
                             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)
    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
    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,
                                                    const SnConfigFrame& curConf,
                                                    SnEventFrame& evt,
                                                    SnPowerFrame& pow,
                                                    char* const genBuf,
                                                    uint32_t nevts,
                                                    const uint32_t timeout_clock) {
    // firstEvt==0 ==> start at beginning
    // nevts==0 ==> all events
    
#ifdef DEBUG
    printf("SendFileContents (byte streaming)\r\n");
#endif
    
    // 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;
    int msiz, mlen;
    
    // 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, timeout_clock);
        ok &= (msiz+SnHeaderFrame::SizeOf())==mlen;
        
#ifdef DEBUG
        printf("sent file header. ok=%d\r\n",(int)ok);
#endif
        
        // the header info for each block
        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
                && (feof(inf)==0)
                && (ferror(inf)==0)
                && ((ftell(inf)+SnHeaderFrame::SizeOf())<=fend) ) {
            // 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 (ok) {
                // send the block
                // TODO: repack events?
                msiz = hlen + SnHeaderFrame::SizeOf();
                mlen = SendFileBlock(inf, hcode, hlen, genBuf, timeout_clock);
                ok &= msiz==mlen;
                if (ok) {
                    if (hcode==SnHeaderFrame::kEventCode) {
                        ++evtsSent;
                        if (nevts>0) {
                            if (evtsSent>=nevts) {
#ifdef DEBUG
                                printf("send %u events. stop\r\n",evtsSent);
#endif
                                break;
                            }
                        }
                    } else if (hcode==SnHeaderFrame::kPowerCode) {
                        ++powsSent;
                    }
                } else {
#ifdef DEBUG
                    printf("not ok when sending hcode=%02x\r\n",hcode);
#endif
                }
            }
        }
        
#ifdef DEBUG
        printf("loop done. ok=%d\r\n",(int)ok);
#endif
        
        // 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 = SendAll(genBuf, msiz, timeout_clock);
        ok &= msiz==mlen;

#ifdef DEBUG
        printf("ok=%d (msiz=%d, mlen=%d)\r\n", (int)ok, msiz, mlen);
#endif
        
        // 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 = SendAll(genBuf, msiz, timeout_clock);
        ok &= msiz==mlen;
        
#ifdef DEBUG
        printf("ok=%d (msiz=%d, mlen=%d)\r\n", (int)ok, 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 ok ? SnCommWin::kOkMsgSent : SnCommWin::kFailPartSent;
}

/*
SnCommWin::ECommWinResult SnCommWin::SendFileContents(FILE* inf,
                                                    const SnConfigFrame& curConf,
                                                    SnEventFrame& evt,
                                                    SnPowerFrame& pow,
                                                    char* const genBuf,
                                                    uint32_t nevts,
                                                    const uint32_t timeout_clock,
                                                    const uint32_t firstEvt) {
    printf("comm win send file contents\r\n");
    // firstEvt==0 ==> start at beginning
    // nevts==0 ==> all events
    
    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
    printf("fend=%d\r\n",fend);
    printf("fpos=%d\r\n",fpos);
    // get file header
    uint64_t macadr;
    uint32_t run;
    uint16_t seq;
    bool ok = (ftell(inf)+SnSDUtils::SizeOfFileHeader(SnSDUtils::kIOvers))<=fend;
    if (ok) {
        SnSDUtils::ReadFileHeader(inf, macadr, run, seq, &pow);
        printf("read file header: run %u, seq %hu\r\n",run,seq);
    }
    
    printf(">>> file hdr read ftell(inf)=%d\r\n",ftell(inf));
    
    // check block
    uint8_t hcode;
    uint32_t hlen;
    ok &= (ftell(inf)+SnHeaderFrame::SizeOf())<=fend;
    if (ok) {
        SnSDUtils::ReadBlockHeader(inf, hcode, hlen);
        printf("read block hd %02x, len %u\r\n",hcode,hlen);
        if (hcode==SnHeaderFrame::kPowerCode) {
            ok &= (ftell(inf)+SnPowerFrame::SizeOf(SnPowerFrame::kIOvers))<=fend;
            if (ok) {
                pow.ReadFrom(inf);
                printf("read power: v1=%g, v2=%g\r\n",pow.GetAveV1(), pow.GetAveV2());
                // now read the next header
                ok &= (ftell(inf)+SnHeaderFrame::SizeOf())<=fend;
                if (ok) {
                    SnSDUtils::ReadBlockHeader(inf, hcode, hlen);
                    printf("read new header: hc %02x, hlen=%u\r\n",hcode,hlen);
                }
            }
        }
    }
    
    printf(">>> power tried ftell(inf)=%d\r\n",ftell(inf));
    
    printf("hcode=%02x\r\n",hcode);
    printf("ok=%d\r\n",(int)ok);
    printf("feof=%d\r\n",feof(inf));
    printf("ferror=%d\r\n",ferror(inf));
    printf("%d+%u <= %d ? %d\r\n",ftell(inf),hlen,fend,
        (int)((ftell(inf)+hlen)<=fend));
    
    // TODO: check memory for temporary config/event frames?
    // get config
    while ((hcode!=SnHeaderFrame::kConfigCode)
            && ok
            && (feof(inf)==0)
            && (ferror(inf)==0)
            && ((ftell(inf)+hlen) <= fend) ) {
        printf("skip: ftell=%d, hlen=%u\r\n",ftell(inf),hlen);
        fseek(inf, hlen, SEEK_CUR); // skip this block
        ok = (ftell(inf)+SnHeaderFrame::SizeOf())<=fend;
        if (ok) {
            SnSDUtils::ReadBlockHeader(inf, hcode, hlen);
            printf("hcs >>> ftell(inf)=%d, hcode=%02x, hlen=%u\r\n",ftell(inf),hcode,hlen);
            printf("feof=%d, ferror=%d\r\n",feof(inf),ferror(inf));
        }
    }
    
    printf("checking ftell\r\n");
    bool gotConf = false;
    ok = (ftell(inf)+hlen) <= fend;
    printf("making temp config\r\n");
    SnConfigFrame conf; // TODO: SOMETIMES STALLS HERE!
    printf("trying to read\r\n");
    if (ok && (hcode==SnHeaderFrame::kConfigCode)) {
        printf("reading config from ftell=%d, hcode=%02x, hlen=%u, ok=%d\r\n",
            ftell(inf), hcode, hlen, (int)ok);
        conf.ReadFrom(inf);
        gotConf = (ftell(inf) <= fend) && (feof(inf)==0) && (ferror(inf)==0);
    }
    printf(">>> conf. ftell(inf)=%d, gotconf=%d\r\n",ftell(inf),(int)gotConf);
    
    char* b = genBuf;
    int msiz, mlen;
    if (ok && gotConf) {
        // get event size
        uint8_t sLoseLSB=0, sLoseMSB=0;
        uint16_t sWvBase=0;
        curConf.GetPackParsFor(GetCommType(), sLoseLSB, sLoseMSB, sWvBase);
        
        // size of event in file
        const uint32_t esize = SnEventFrame::SizeOf(SnEventFrame::kIOVers,
                                                    conf.GetWvLoseLSB(),
                                                    conf.GetWvLoseMSB());
        
        printf("esize=%u\r\n",esize);
            
        // number of events / power readings we will send
        uint32_t evtsSent=0, powsSent=0;
        b = genBuf;
        // send the file header
        SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFileHeadrCode,
                               SnSDUtils::SizeOfFileHeader(SnSDUtils::kIOvers));
        SnSDUtils::WriteFileHeader(b, macadr, run, seq);
        msiz = b-genBuf;
        mlen = SendAll(genBuf, msiz, timeout_clock);
        if (mlen==msiz) {
            // send power header
            b = genBuf;
            SnHeaderFrame::WriteTo(b, SnHeaderFrame::kPowerCode, 
                                   pow.SizeOf(SnPowerFrame::kIOvers));
            pow.WriteTo(b);
            msiz = b-genBuf;
            mlen = SendAll(genBuf, msiz, timeout_clock);
            ++powsSent;
            if (mlen==msiz) {
                // send the config
                b = genBuf;
                SnHeaderFrame::WriteTo(b, SnHeaderFrame::kConfigCode, 
                                       conf.SizeOf(SnConfigFrame::kIOVers));
                conf.WriteTo(b);
                msiz = b-genBuf;
                mlen = SendAll(genBuf, msiz, timeout_clock);
                if (mlen==msiz) {
                    ok = true;
                }
            }
        }
            
        printf("ok=%d, nevts=%u\r\n",(int)ok,nevts);
        
        if (ok) {
            // size of event sent over afar
            const uint32_t ssize = SnEventFrame::SizeOf(SnEventFrame::kIOVers,
                                                        sLoseLSB, sLoseMSB);
            
            // loop over blocks. send event & power frames
            // until EOF or nevets have been sent
            uint8_t hc; uint32_t hl;
            while (ok && (feof(inf)==0) 
                      && (ferror(inf)==0)
                      && (ftell(inf)<fend) ) { // feof doesn't seem to work
                printf(">>> ftell(inf)=%d\r\n",ftell(inf));
                if ((ftell(inf)+SnHeaderFrame::SizeOf())<=fend) {
                    SnSDUtils::ReadBlockHeader(inf, hc, hl);
                    if (hc==SnHeaderFrame::kEventCode) {
                        if ((ftell(inf)+ssize)<=fend) {
                            evt.ReadFrom(inf, genBuf,
                                conf.GetWvLoseLSB(), conf.GetWvLoseMSB(),
                                conf.GetWvBaseline());
                            if (evt.GetEvtNum()>=firstEvt) {
                                ++evtsSent;
                                printf("sending evt %u\r\n",evtsSent);
                                // must be after evt.Read, since that uses the buffer
                                b = genBuf;
                                SnHeaderFrame::WriteTo(b, SnHeaderFrame::kEventCode, ssize);
                                evt.WriteTo(b, sLoseLSB, sLoseMSB, sWvBase); // will repack if necessary
                                msiz = b-genBuf; //SnHeaderFrame::SizeOf()+ssize;
                                mlen = SendAll(genBuf, msiz, timeout_clock);
                                ok &= mlen==msiz;
                            }
                        } else {
                            printf("event header, but not enough bytes in file\r\n");
                            ok = false;
                        }
                    } else if (hc==SnHeaderFrame::kPowerCode) {
                        if ((ftell(inf)+SnPowerFrame::SizeOf(SnPowerFrame::kIOvers))<=fend) {
                            ++powsSent;
                            pow.ReadFrom(inf);
                            printf("sending power frame %u, v1=%g, v2=%g, t=%u\r\n",
                                powsSent, pow.GetAveV1(), pow.GetAveV2(), pow.GetTime());
                            b = genBuf;
                            SnHeaderFrame::WriteTo(b, SnHeaderFrame::kPowerCode, 
                                SnPowerFrame::SizeOf(SnPowerFrame::kIOvers));
                            pow.WriteTo(b);
                            msiz = b-genBuf;
                            mlen = SendAll(genBuf, msiz, timeout_clock);
                            ok &= mlen==msiz;
                        } else {
                            printf("power header, but not enough bytes in file\r\n");
                            ok = false;
                        }
                    } else {
                        printf("unhandled block. hc=%hhu, hl=%u\r\n",
                            hc, hl);
                        if ((ftell(inf)+hl)<=fend) {
                            fseek(inf, hl, SEEK_CUR); // skip this block
                        } else {
                            printf("not enough bytes in file to skip block\r\n");
                            ok = false;
                        }
                    }
                } else {
                    printf("not enough bytes in file to read header\r\n");
                    printf("feof=%d\r\n",feof(inf));
                    printf("ftell(inf)=%d, hdr size=%u, fend=%u\r\n",
                        (ftell(inf)), SnHeaderFrame::SizeOf(), fend);
                    ok = false;
                }
            }
            // send number of events sent
            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;
            // send number of power readings sent
            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;
        }
    } else {
        printf("failed to get config from file\r\n");
        // send corrupted file handshake
        b = genBuf;
        SnHeaderFrame::WriteTo(b, SnHeaderFrame::kFileReadFailCode, 0u);
        msiz = b-genBuf;
        mlen = SendAll(genBuf, msiz, timeout_clock);
        ok &= msiz==mlen;
    }
    
    // put file position back
    fseek(inf, fpos, SEEK_SET);
    
    return ok ? SnCommWin::kOkMsgSent : SnCommWin::kFailPartSent;
}
*/