/// /// \file zbsdtHelper.h /// \author Jan Chrin, PSI /// \date Release: January 2018 /// \version CAFE 1.6 #ifndef ZBSDTHELPER_H #define ZBSDTHELPER_H #include #include namespace CAFE_BSHELPER { using boost::multi_index_container; using namespace boost::multi_index; bsreadContainer_set bsdt; std::vector bsrdV; //Type maching is as follows: // int8 [1 byte] to char // uint8 [1] to unsigned char // int16 [2] to short // uint16 [2] to unsigned short // int32 [4] to long // uint32 [4] to unsigned long // int64 [8] to long long // uint64 [8] to unsigned long long // float32[4] to float // float64[8] to double // bool [1] same as uint8; 0=false, !0 = true // string to char (Byte order of strings are irrelevant - always big-endian). The String encoding is utf8; from bsread documentation enum bsdtIndex {BS_INT8=0, BS_UINT8, BS_INT16, BS_UINT16, BS_INT32, BS_UINT32, BS_INT64, BS_UINT64, BS_FLOAT32, BS_FLOAT64, BS_BOOL, BS_STRING, BS_CHAR=BS_STRING }; void bsdtInsert() { bsdt.insert(bsreadContainer(BS_INT8, "int8")); bsdt.insert(bsreadContainer(BS_UINT8, "uint8")); bsdt.insert(bsreadContainer(BS_INT16, "int16")); bsdt.insert(bsreadContainer(BS_UINT16, "uint16")); bsdt.insert(bsreadContainer(BS_INT32, "int32")); bsdt.insert(bsreadContainer(BS_UINT32, "uint32")); bsdt.insert(bsreadContainer(BS_INT64, "int64")); bsdt.insert(bsreadContainer(BS_UINT64, "uint64")); bsdt.insert(bsreadContainer(BS_FLOAT32,"float32")); bsdt.insert(bsreadContainer(BS_FLOAT64,"float64")); bsdt.insert(bsreadContainer(BS_BOOL, "bool")); bsdt.insert(bsreadContainer(BS_STRING, "string")); bsdt.insert(bsreadContainer(BS_CHAR, "string")); } int getByteSize(unsigned int dt) { #define __METHOD__ "getByteSize (unsigned int)" switch(dt) { case BS_INT8: return sizeof(int8_t); case BS_UINT8: case BS_BOOL: return sizeof(uint8_t); case BS_INT16: return sizeof(int16_t); case BS_UINT16: return sizeof(uint16_t); case BS_INT32: return sizeof(int32_t); case BS_UINT32: return sizeof(uint32_t); case BS_INT64: return sizeof(int64_t); case BS_UINT64: return sizeof(uint64_t); case BS_FLOAT32: return sizeof(float); case BS_FLOAT64: return sizeof(double); case BS_STRING: //is also BS_CHAR return sizeof(char); default: std::cout << __FILE__ << "//" << __LINE__ << "//" << __METHOD__ << std::endl; std::cout << "Enumerated input value " << dt << " is outside allowed band: " << BS_INT8 << " and " << BS_STRING << std::endl; print_out_by(bsdt); std::cout << "Returning byte size of 1" << std::endl; return 1; } #undef __METHOD__ } int getByteSize(std::string dt) { #define __METHOD__ "getByteSize (string)" bsreadContainer_set_by_name & name_index = bsdt.get (); bsreadContainer_set_by_name::iterator it_name; unsigned int bsdtIndex; //Find enum of data type it_name = name_index.find(dt); if ( (it_name) != name_index.end() ) { bsdtIndex=(*it_name).by_bsID; return getByteSize(bsdtIndex); } std::cout << __FILE__ << "//" << __LINE__ << "//" << __METHOD__ << std::endl; std::cout << "string value " << dt << " is not recognized " << std::endl; print_out_by(bsdt); std::cout << "Returning byte size of 1" << std::endl; return 1; #undef __METHOD__ } //Easy show-error-and-bail function. //void run_screaming(const char *message, const int code) { // printf("%s\n", message); // exit(code); // return; //} /** * \brief Generic function to display bits of a number * used for testing in zmq stream */ void printBits(int const size, void const * const ptr) { unsigned char *b= (unsigned char *) ptr; unsigned char byte; int i, j; for (i=size-1; i>=0; i--) { for (j=7; j>=0; j--) { byte =(b[i]>>j ) &1; printf("%u", byte); } } puts(""); return; } /** * \brief Returns true if at least one bit within byte is set * Used to test endianess of timestamp */ bool hasMinOneBitSet(int const size, void const * const ptr) { unsigned char *b= (unsigned char *) ptr; unsigned char byte; bool hasBit = false; int i, j; for (i=size-1; i>=0; i--) { for (j=7; j>=0; j--) { byte =(b[i]>>j ) &1; if (byte) { return true; } } } return false; } /** * \brief Unfolds the two bytes that precede the blob * See: https://git.psi.ch/sf_daq/ch.psi.daq.dispatcherrest * and: https://git.psi.ch/sf_daq/bsread_specification */ int unfoldPreBlob(const char * data, long &uncompressedSize, int &blockSize) { //Check for -ve numbers uncompressedSize = ( ((data[7] <<0) & 0x7f) | ((data[7]<<0) & 0x80) | (data[6]<<8) | (data[5]<<16) | (data[4]<<24) | ((long long) data[3]<<32) | ((long long) data[2]<<40) | ((long long) data[1]<<48) | ((long long) data[0]<<56) ) ; // printBits(2, &uncompressedSize); //std::cout << "UNCOMPRESSED SIZE / " << uncompressedSizeL << " " << uncompressedSize << std::endl; //uncompressedSize = ( ((data[7] <<0) & 0x7f) | ((data[7]<<0) & 0x80) | (data[6]<<8) | (data[5]<<16) | (data[4]<<24) // | ((long long) data[3]<<32) | ((long long) data[2]<<40) | ((long long) data[1]<<48) | ((long long) data[0]<<56) ) ; //std::cout << "UNCOMPRESSED SIZE // " << uncompressedSize << std::endl; //All three give equivalent block size //blockSize= ( (data[11]<<0) | (data[10]<<8) | (data[9]<<16) | (data[8]<<24) ); //std::cout << "BLOCKSIZE " << blockSize << std::endl; blockSize= ( ((data[11]<<0)) | ((data[11]<<0)& 0x80) | (data[10]<<8) | (data[9]<<16) | (data[8]<<24) ); //std::cout << "BLOCKSIZE / " << blockSize << std::endl; //blockSize= ( ((data[11]<<0) & 0x7f) | ((data[11]<<0)& 0x80) | (data[10]<<8) | (data[9]<<16) | (data[8]<<24) ); //std::cout << "BLOCKSIZE // " << blockSize << std::endl; return ICAFE_NORMAL;; } /** * \brief DataBitset Template \n * CTYPE is the integer type the data type is to be rendered to the client \n * method unfold() will receive data and then convert to CTYPE */ template class DataBitset { public: DataBitset () {}; ~DataBitset () {}; CTYPE unfold(char * data, size_t start, size_t end, std::string encoding ) { //std::cout << "encoding=" << encoding << std::endl; if (encoding=="big") { //big endian for (short n=start; n < end; n++) { i = (i << 8) + data[n]; } } else { //little endian for (short n = end; n >= start; n--) { i = (i << 8) + data[n]; } } //std::cout << "Value = " << i << std::endl; return i; } private: CTYPE i; }; /** * \brief IntegerBitset Template \n * CTYPE is the integer type the data type is to be rendered to the client \n * method unfold() will receive data and then convert to vector */ template class IntegerBitsetV { public: IntegerBitsetV () {}; ~IntegerBitsetV () {}; CTYPE unfold(char * data, unsigned int nelem, std::string encoding, std::vector &valV ) { valV.clear(); valV.reserve(nelem); cSize=sizeof(CTYPE); idx=0; if (encoding=="big") { switch (cSize) { case 1: for (unsigned int i=0; i class IntegerBitset { public: IntegerBitset () {}; ~IntegerBitset () {}; CTYPE * unfold(char * data, unsigned int nelem, std::string encoding ) { //std::cout << sizeof(char) << " s+ " << sizeof(short) << " i+ " << sizeof(int) << " l+ " < class FloatBitset { public: FloatBitset () {}; ~FloatBitset () {}; CTYPE * unfold(char * data, unsigned int nelem, std::string encoding) { cSize=sizeof(CTYPE); val=new CTYPE[nelem]; //std::cout << "HELPER>H " << nelem << " " << encoding << " cSize " << cSize << std::endl; if (encoding=="big") { for (unsigned int i=0; i */ template class FloatBitsetV { public: FloatBitsetV () {}; ~FloatBitsetV () {}; CTYPE unfold(char * data, unsigned int nelem, std::string encoding, std::vector &valV) { //memory already allocated in zbsread.h //valV.clear(); //valV.reserve(nelem); cSize=sizeof(CTYPE); //std::cout << "HELPER_H " << nelem << " " << encoding << " cSize " << cSize << std::endl; if (encoding=="big") { for (unsigned int i=0; i