Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

SnEventFrame.cpp

Committer:
uci1
Date:
2019-06-05
Revision:
125:ce4045184366
Parent:
119:b3d7699d0eb0

File content as of revision 125:ce4045184366:

#include "SnEventFrame.h"

#include "SnCRCUtils.h"

//#define DEBUG

#if CHIPBOARD==ATWD4CH
const uint8_t     SnEventFrame::kIOVers = 1;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#elif CHIPBOARD==SST4CH
const uint8_t     SnEventFrame::kIOVers = 2;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#elif CHIPBOARD==SST4CH_1GHz
const uint8_t     SnEventFrame::kIOVers = 3;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#elif CHIPBOARD==SST4CH512
const uint8_t     SnEventFrame::kIOVers = 4;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#elif CHIPBOARD==SST4CH512_1GHz
const uint8_t     SnEventFrame::kIOVers = 5;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#elif CHIPBOARD==SST8CH
const uint8_t     SnEventFrame::kIOVers = 6;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#elif CHIPBOARD==SST8CH_1GHz
const uint8_t     SnEventFrame::kIOVers = 7;   // MUST BE INCREASED if any member var changes (==> also if kNchans, etc. change!)
#else
#error CHIPBOARD value not accounted for in event frame i/o version.
#endif

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) {

        const uint16_t nsamps = GetTotSamplesForIOVers(Rv);

        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, nsamps);
        b.s       = SnBitUtils::ReadFrom(b.s, fCRC);

#if CHIPBOARD!=ATWD4CH
        const uint16_t nstopBytes = GetStopBytesForIOVersBufferSafe(Rv);
        if (Rv>1) {
            b.s   = SnBitUtils::ReadFrom(b.s, fStop, nstopBytes);
        }
#endif
    }
    
    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

    const uint16_t nsamps = GetTotSamplesForIOVers(kIOVers);
    
    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, nsamps);
    b.s           = SnBitUtils::WriteTo(b.s, fCRC);

#if CHIPBOARD!=ATWD4CH
    const uint16_t nstopBytes = GetStopBytesForIOVersBufferSafe(kIOVers);
    if (kIOVers>1) {
        // we test kIOVers rather than the CHIPBOARD #define in order
        // to ensure that the i/o version is the ONLY variable that determines
        // what the event looks like in a file or communication.
        // this is the only way to ensure readability going forward.
#ifdef DEBUG
        printf("kNstopBytes=%hu, nstopBytes=%hu, kIOVers=%hhu\r\n",
            kNstopBytes, nstopBytes, kIOVers);
        char* x = b.s;
#endif
        b.s       = SnBitUtils::WriteTo(b.s, fStop, nstopBytes);
#ifdef DEBUG
        printf("wrote %d stop bytes\r\n", b.s - x);
#endif
    }
#endif

#ifdef DEBUG
    printf("SnEventFrame::WriteTo:\r\n");
    for (uint32_t i=0; i<b.s-buf; i++) {
        printf("%02X ",buf[i]);
    }
    printf("\r\n");
#endif
    
    return b.s;
}

void SnEventFrame::CalcCRC() {
    // CRC made using union on a little endian (mbed) processor
    fCRC = SnCRCUtils::GetCRC32for(fData, kTotSamps);
#if CHIPBOARD!=ATWD4CH
    fCRC = SnCRCUtils::GetUpdatedCRC32for(fCRC, fStop, kNstopBytes);
#endif
#ifdef DEBUG
    printf("SnEventFrame::CalcCRC  crc=%u\r\n",fCRC);
#endif
}

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)!=0) {
            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,
                                 const uint16_t nsamps) {
    // 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<nsamps; ++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,
                                         const uint16_t nsamps) {
    if (loseLSB==0 && loseMSB==0 && wvBaseline==0) {
        memcpy(data, buf, nsamps*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, nsamps*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<nsamps; ++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);
}