Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

SnEventFrame.cpp

Committer:
uci1
Date:
2012-08-08
Revision:
8:95a325df1f6b
Parent:
3:24c5f0f50bf1
Child:
21:ce51bb0ba4a5

File content as of revision 8:95a325df1f6b:

#include "SnEventFrame.h"

#include "SnCRCUtils.h"

const uint8_t     SnEventFrame::kIOVers = 1;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)

const char* SnEventFrame::ReadFrom(const char* const buf,
                                   const uint8_t loseLSB, const uint8_t loseMSB,
                                   const uint16_t wvBaseline) {
    // no check on the length of buf is done here
    // that should be been done already
    //
    // must match ::WriteToBuf
    
    // NOTE: on the mbed, this is reduntant (char is unsigned)
    // but this way, the block can be copied to other computers
    // and still work.
    union Usub {
        const char* s;
        const uint8_t* u;
    } b;
    b.s = buf;
    
    uint8_t Rv=0;
    b.s           = SnBitUtils::ReadFrom(b.s, Rv); // i/o version
    if (Rv>0) {
        b.s       = SnBitUtils::ReadFrom(b.s, fMbedTime);
        b.s       = SnBitUtils::ReadFrom(b.s, fEvtNum);
        b.s       = SnBitUtils::ReadFrom(b.s, fDTms);
        b.s       = SnBitUtils::ReadFrom(b.s, fTrgNum);
        b.s       = SnBitUtils::ReadFrom(b.s, fTrgBits);
        b.u       = UnpackWavef(b.u, fData, loseLSB, loseMSB, wvBaseline);
        b.s       = SnBitUtils::ReadFrom(b.s, fCRC);
    }
    
    return b.s;
}

char* SnEventFrame::WriteTo(char* const buf,
                            const uint8_t loseLSB, const uint8_t loseMSB,
                            const uint16_t wvBaseline) const {
    // no check on the length of the buf is done here
    // that should be done already
    //
    // must match ReadFromBuf
    
    // NOTE: on the mbed, this is reduntant (char is unsigned)
    // but this way, the block can be copied to other computers
    // and still work.
    union {
        char* s;
        uint8_t* u;
    } b;
    b.s = buf;
    
    b.s           = SnBitUtils::WriteTo(b.s, kIOVers); // i/o version

    b.s           = SnBitUtils::WriteTo(b.s, fMbedTime);
    b.s           = SnBitUtils::WriteTo(b.s, fEvtNum);
    b.s           = SnBitUtils::WriteTo(b.s, fDTms);
    b.s           = SnBitUtils::WriteTo(b.s, fTrgNum);
    b.s           = SnBitUtils::WriteTo(b.s, fTrgBits);
    b.u           = PackWavef(b.u, fData, loseLSB, loseMSB, wvBaseline);
    b.s           = SnBitUtils::WriteTo(b.s, fCRC);
    
    return b.s;
}

void SnEventFrame::CalcCRC() {
    // CRC made using union on a little endian (mbed) processor
    fCRC = 0u;
    const uint16_t* dev = fData;
    for (uint16_t i=0; i<kTotSamps; i++, dev++) {
        fCRC = update_crc32_xfer_short(fCRC, *dev);
    }
}

bool SnEventFrame::ReadFromFileToBuf(FILE* f,
                                     char* const evtBuf,
                                     const uint8_t loseLSB,
                                     const uint8_t loseMSB) {
    // file position expected to be at this event frame already
    bool ret = false;
    if (f!=0) {
        if (fread(evtBuf, SizeOf(kIOVers, loseLSB, loseMSB), 1u, f)!=NULL) {
            ret = true;
        }
    }
    return ret;
}

bool SnEventFrame::ReadFrom(FILE* f,
                            char* const evtBuf,
                            const uint8_t loseLSB, const uint8_t loseMSB,
                            const uint16_t wvBaseline) {
    // file position expected to be at this event frame already
    const bool ret = ReadFromFileToBuf(f, evtBuf, loseLSB, loseMSB);
    if (ret) {
        ReadFrom(evtBuf, loseLSB, loseMSB, wvBaseline);
    }
    return ret;
}

bool SnEventFrame::WriteTo(FILE* f, char* const evtBuf,
                           const uint8_t loseLSB, const uint8_t loseMSB,
                           const uint16_t wvBaseline) const {
    // file pointer should be in correct location
    
    WriteTo(evtBuf, loseLSB, loseMSB, wvBaseline);
    return WriteToFileFromBuf(f, evtBuf, loseLSB, loseMSB);
}

bool SnEventFrame::WriteToFileFromBuf(FILE* f, char* const evtBuf,
                               const uint8_t loseLSB, const uint8_t loseMSB) {
    // file pointer should be in correct location
    
    bool ret = false;
    if (f!=0) {
        fwrite(evtBuf, SizeOf(kIOVers, loseLSB, loseMSB), 1u, f);
        ret = (ferror(f)==false);
    }
    return ret;

}


uint8_t* SnEventFrame::PackWavef(uint8_t* const buf, const uint16_t* const data,
                                 const uint8_t loseLSB, const uint8_t loseMSB,
                                 const uint16_t wvBaseline) {
    // Compress the data. This is potentially LOSSY; it depends
    // on the dynamic range and on the options.
    // See SnConfigFrame::fWvLoseLSB and SnConfigFrame::fWvLoseMSB.
    // If the number of least signficant bits to lose is not 0, the
    // compression will be lossy (decreased resolution -- this is ok
    // if the noise of the signal is much greater than the resolution).
    // Losing the most significant bits will only be lossy if the
    // signal-SnConfigFrame::fWvBaseline cannot fit in the reduced
    // dynamic range (each MSB bit reducing the DR by a factor of 2).
    //
    // Note that the mbed uses little endian. Behavior should be the
    // same on big endian, but this has not been tested.
    //
    // Use an unsigned buffer to prevent bits being changed during
    // an implicit unsigned -> signed cast.
    //
    // buf = the byte array into which the data should be packed
    // data = the data to pack
    // loseLSB = number of least significant bits to throw away
    // loseMSB = number of most significant bits to throw away
    // wvBaseline = baseline to subtract to from ADC before packing
    
    const uint32_t blen = SizeOfPackedWavef(loseLSB, loseMSB);
    const uint8_t packSmpBits = BITS_IN_SHORT-loseLSB-loseMSB;

    // make sure this buffer space is all 0's to start
    memset(buf, 0, blen*sizeof(uint8_t));
    
    const uint16_t clipHi = uint16_t(
       uint16_t(uint16_t(0xFFFFu >> loseLSB) << (loseLSB+loseMSB))
                >> loseMSB);
    
    uint8_t* b = buf;
    const uint16_t* dev = data;
    uint16_t dum;
    int8_t sbit=0;
    for (uint16_t i=0; i<kTotSamps; i++, dev++) {
        // dump the bits we don't want
        dum = (*dev) - wvBaseline;
        if (dum<clipHi) {
          dum >>= loseLSB;
          dum <<= (loseLSB+loseMSB);
        } else {
          dum = clipHi << loseMSB;
        }
        if (sbit<=0) {
            // lose MSB's put in previous short (or none if sbit==0)
            dum   <<= -sbit;
            *b     |= dum >> 8u;         // "first" byte of the short
            dum   <<= 8u;
            *(b+1) |= dum >> 8u;   // "second"
            // move to next number (dev++ in the for loop)
            // move starting bit up
            // but stay in this byte of the buf (do not increment b)
            // since kPackSmpBits <= kBitsInShort, sbit can't
            // move past the end of the current two bytes
            sbit += packSmpBits;
        } else {
            // first few bits towards the end of this short
            dum   >>= sbit;
            *b     |= dum >> 8u;         // "first" byte of the short
            dum   <<= 8u;
            *(b+1) |= dum >> 8u;   // "second"
            if ( (sbit+packSmpBits) >= BITS_IN_SHORT ) {
               b+=2;       // move to next short in the buf
               i--; dev--; // but stay on this number
               // move starting bit back into the short we just filled
               sbit -= BITS_IN_SHORT;
            } else {
               // stay in this buffer and move to the next number
               // move starting bit up
               sbit += packSmpBits;
            }
        }
    }
    
    return buf+blen;
}

const uint8_t* SnEventFrame::UnpackWavef(const uint8_t* const buf,
                                         uint16_t* const data,
                                         const uint8_t loseLSB,
                                         const uint8_t loseMSB,
                                         const uint16_t wvBaseline) {
    if (loseLSB==0 && loseMSB==0 && wvBaseline==0) {
        memcpy(data, buf, kTotSamps*sizeof(uint16_t));
    } else {

        const uint8_t packSmpBits = BITS_IN_SHORT-loseLSB-loseMSB;
    
        // make sure data is all 0's to start
        memset(data, 0, kTotSamps*sizeof(uint16_t));
        
        const uint8_t* b = buf;
        uint16_t* dev = data;
        uint16_t dum;
        int8_t sbit=0;
        for (uint16_t i=0; i<kTotSamps; i++, dev++) {
            dum  = (*b) << 8u;
            dum |= *(b+1);
            if (sbit<=0) {
                dum >>= (-sbit+loseLSB+loseMSB);
                dum <<= loseLSB;
                *dev |= dum;
                // add baseline and move to next number (dev++ in the for loop)
                *dev += wvBaseline;
                // but stay in this short of the buf (do not increment b)
                // move starting bit up
                sbit += packSmpBits;
            } else {
                dum <<= sbit;
                dum >>= loseMSB+loseLSB;
                dum <<= loseLSB;
                *dev = dum;
                if ( (sbit+packSmpBits) >= BITS_IN_SHORT ) {
                   b+=2;       // move to next short in the buf
                   i--; dev--; // but stay on this number
                   // move starting bit back into the short we just read from
                   sbit -= BITS_IN_SHORT;
                } else {
                   // add baseline and move to next number (dev++ in the for loop)
                   *dev += wvBaseline;
                   sbit += packSmpBits;
                }
            } 
        }
    }
    
    return buf+SizeOfPackedWavef(loseLSB, loseMSB);
}