├── cSpectrometerOverflowRegisters.h ├── cSpectrometerOverflowRegisters.cpp ├── SpectrometerDefinitions.h ├── ByteSwap.h ├── SpectrometerHeader.h ├── SpectrometerDefinitions.cpp ├── SpectrometerHeader.cpp ├── SpectrometerDataStreamInterpreter.h ├── SpectrometerDataStreamInterpreter.cpp ├── SpectrometerHDF5OutputFile.h └── SpectrometerHDF5OutputFile.cpp /cSpectrometerOverflowRegisters.h: -------------------------------------------------------------------------------- 1 | #ifndef SPECTROMETER_OVERFLOW_REGISTERS_H 2 | #define SPECTROMETER_OVERFLOW_REGISTERS_H 3 | 4 | #include 5 | 6 | struct cSpectrometerOverflowRegisters 7 | { 8 | cSpectrometerOverflowRegisters(uint32_t u32RoachOverflowRegisters); 9 | 10 | bool m_bADC0OverRange; 11 | bool m_bADC1OverRange; 12 | bool m_bCoarseFFT0Overflow; 13 | bool m_bCoarseFFT1Overflow; 14 | bool m_bPacketiserOverflow; 15 | bool m_bQueueFull; 16 | bool m_b10GbETxOverflow; 17 | }; 18 | 19 | #endif // SPECTROMETER_OVERFLOW_REGISTERS_H 20 | -------------------------------------------------------------------------------- /cSpectrometerOverflowRegisters.cpp: -------------------------------------------------------------------------------- 1 | #include "cSpectrometerOverflowRegisters.h" 2 | 3 | cSpectrometerOverflowRegisters::cSpectrometerOverflowRegisters(uint32_t u32RoachOverflowRegisters) 4 | { 5 | m_bADC0OverRange = ( (u32RoachOverflowRegisters & 0x00000001) == 0x00000001 ); 6 | m_bADC1OverRange = ( (u32RoachOverflowRegisters & 0x00000002) == 0x00000002 ); 7 | m_bCoarseFFT0Overflow = ( (u32RoachOverflowRegisters & 0x00000004) == 0x00000004 ); 8 | m_bCoarseFFT1Overflow = ( (u32RoachOverflowRegisters & 0x00000008) == 0x00000008 ); 9 | m_bPacketiserOverflow = ( (u32RoachOverflowRegisters & 0x00000010) == 0x00000010 ); 10 | m_bQueueFull = ( (u32RoachOverflowRegisters & 0x00000020) == 0x00000020 ); 11 | m_b10GbETxOverflow = ( (u32RoachOverflowRegisters & 0x00000040) == 0x00000040 ); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /SpectrometerDefinitions.h: -------------------------------------------------------------------------------- 1 | #ifndef SPECTROMETER_DEFINITIONS 2 | #define SPECTROMETER_DEFINITIONS 3 | 4 | //System includes 5 | #include 6 | #include 7 | 8 | //Library includes 9 | 10 | //Local includes 11 | 12 | namespace AVN 13 | { 14 | 15 | namespace Spectrometer 16 | { 17 | 18 | static const uint32_t HEADER_SIZE_B = 16; 19 | static const uint32_t SYNC_WORD = 0x1a2b3c4d; 20 | 21 | enum digitiserType 22 | { 23 | WB_SPECTROMETER_LRPP = 0, 24 | WB_SPECTROMETER_LRQU = 1, 25 | NB_SPECTROMETER_LRPP = 2, 26 | NB_SPECTROMETER_LRQU = 3, 27 | UNDEFINED = 0xffff 28 | }; 29 | 30 | std::string digitiserTypeToString(uint16_t u16DigitiserType); 31 | 32 | std::string getDigitiserChannelName(uint16_t u16DigitiserType, uint32_t u32ChanNo); 33 | 34 | uint32_t getDigitiserFrameSize_nBins(uint16_t u16DigitiserType); 35 | 36 | 37 | } // namespace Spectrometer 38 | 39 | } // namespace AVN 40 | 41 | #endif //SPECTROMETER_DEFINITIONS 42 | -------------------------------------------------------------------------------- /ByteSwap.h: -------------------------------------------------------------------------------- 1 | //Manual implementation of byte swap functions for old versions of GCC which don't have them 2 | 3 | #ifndef BYTE_SWAP_H 4 | #define BYTE_SWAP_H 5 | 6 | //System includes 7 | #ifdef _WIN32 8 | #include 9 | #else 10 | #include 11 | #endif 12 | 13 | //Library includes 14 | 15 | //Local includes 16 | 17 | //For *nix flavours 18 | #ifndef _WIN32 19 | 20 | //Get GCC version 21 | #define GCC_VERSION (__GNUC__ * 10000 \ 22 | + __GNUC_MINOR__ * 100 \ 23 | + __GNUC_PATCHLEVEL__) 24 | 25 | //For x86 platforms (assuming nothing else weird is being used...) 26 | #ifndef __amd64__ 27 | 28 | //For GCC <4.8 29 | #if GCC_VERSION < 40800 30 | 31 | #pragma message "Detected GCC < 4.8 on x86, Defining missing 'uint16_t __builtin_bswap16(uint16_t)' function" 32 | 33 | //There is no __builtin_bswap16 for GCC <4.8 in x86 34 | static inline uint16_t __builtin_bswap16(uint16_t u16Value) 35 | { 36 | return ( u16Value << 8 )|( u16Value >> 8 ); 37 | } 38 | 39 | #endif // GCC_VERSION < 40800 40 | 41 | #endif // ! __amd64__ 42 | 43 | #endif // ! WIN32 44 | 45 | #endif //BYTE_SWAP_H 46 | -------------------------------------------------------------------------------- /SpectrometerHeader.h: -------------------------------------------------------------------------------- 1 | #ifndef SPECTROMETER_HEADER 2 | #define SPECTROMETER_HEADER 3 | 4 | //System includes 5 | #include 6 | #include 7 | 8 | //Library includes 9 | 10 | //Local includes 11 | #include "SpectrometerDefinitions.h" 12 | 13 | class cSpectrometerHeader 14 | { 15 | public: 16 | cSpectrometerHeader(const char* pcData); 17 | cSpectrometerHeader(const std::vector &vcData); 18 | cSpectrometerHeader(); 19 | ~cSpectrometerHeader(); 20 | 21 | std::string toString(); 22 | bool deserialise(const char* pcData); 23 | bool deserialise(const std::vector &vcData); 24 | std::vector serialise(); 25 | 26 | //Accessors 27 | uint32_t getSyncWord() const; 28 | int64_t getTimestamp_us() const; 29 | uint8_t getSubframeNumber() const; 30 | uint8_t getNSubframes() const; 31 | uint16_t getDigitiserType() const; 32 | bool getNoiseDiodeOn() const; 33 | 34 | //Mutators 35 | void setSyncWord(uint32_t u32SyncWord = AVN::Spectrometer::SYNC_WORD); 36 | void setTimestamp_us(int64_t i64Timestamp); 37 | void setSubframeNumber(uint8_t u8SubframeNumber); 38 | void setNSubframes(uint8_t u8NSubframes); 39 | void setDigitiserType(uint16_t u16DigitiserType); 40 | void setNoiseDiodeOn(bool bNoiseDiodeOn); 41 | 42 | bool requiresEndianessFlip(); 43 | 44 | bool isValid(); 45 | 46 | private: 47 | uint32_t m_u32SyncWord; 48 | int64_t m_i64tTimestamp_us; 49 | uint8_t m_u8SubframeNumber; 50 | uint8_t m_u8NSubframes; 51 | uint16_t m_u16DigitiserType; 52 | bool m_bNoiseDiodeOn; 53 | 54 | bool m_bFlipEndianess; 55 | 56 | bool m_bValid; 57 | }; 58 | 59 | #endif //SPECTROMETER_HEADER 60 | -------------------------------------------------------------------------------- /SpectrometerDefinitions.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | 4 | //Library includes 5 | 6 | //Local includes 7 | #include "SpectrometerDefinitions.h" 8 | 9 | using namespace AVN::Spectrometer; 10 | using namespace std; 11 | 12 | string AVN::Spectrometer::digitiserTypeToString(uint16_t u16DigitiserType) 13 | { 14 | std::string strDigitiserType; 15 | 16 | switch(u16DigitiserType) 17 | { 18 | case WB_SPECTROMETER_LRPP: 19 | strDigitiserType = std::string("WB spectrometer left and right power, left and right phase"); 20 | break; 21 | 22 | case WB_SPECTROMETER_LRQU: 23 | strDigitiserType = std::string("WB spectrometer left and right power, Stokes Q and U"); 24 | break; 25 | 26 | case NB_SPECTROMETER_LRPP: 27 | strDigitiserType = std::string("NB spectrometer left and right power, left and right phase"); 28 | break; 29 | 30 | case NB_SPECTROMETER_LRQU: 31 | strDigitiserType = std::string("NB spectrometer left and right power, Stokes Q and U"); 32 | break; 33 | 34 | default: 35 | strDigitiserType = std::string("Undefined"); 36 | break; 37 | } 38 | 39 | return strDigitiserType; 40 | } 41 | 42 | string AVN::Spectrometer::getDigitiserChannelName(uint16_t u16DigitiserType, uint32_t u32ChanNo) 43 | { 44 | std::string strDigitiserChannelName; 45 | 46 | switch(u16DigitiserType) 47 | { 48 | case WB_SPECTROMETER_LRQU: 49 | case NB_SPECTROMETER_LRQU: 50 | switch(u32ChanNo) 51 | { 52 | case 0: strDigitiserChannelName = std::string("Left Power"); break; 53 | case 1: strDigitiserChannelName = std::string("Right Power"); break; 54 | case 2: strDigitiserChannelName = std::string("Stokes Q"); break; 55 | case 3: strDigitiserChannelName = std::string("Stokes U"); break; 56 | default: strDigitiserChannelName = std::string("Undefined"); break; 57 | } 58 | break; 59 | 60 | case WB_SPECTROMETER_LRPP: 61 | case NB_SPECTROMETER_LRPP: 62 | switch(u32ChanNo) 63 | { 64 | case 0: strDigitiserChannelName = std::string("Left Power"); break; 65 | case 1: strDigitiserChannelName = std::string("Right Power"); break; 66 | case 2: strDigitiserChannelName = std::string("Left Phase"); break; 67 | case 3: strDigitiserChannelName = std::string("Right Phase"); break; 68 | default: strDigitiserChannelName = std::string("Undefined"); break; 69 | } 70 | break; 71 | 72 | default: 73 | strDigitiserChannelName = std::string("Undefined"); 74 | break; 75 | } 76 | 77 | return strDigitiserChannelName; 78 | } 79 | 80 | uint32_t AVN::Spectrometer::getDigitiserFrameSize_nBins(uint16_t u16DigitiserType) 81 | { 82 | uint32_t u32DigitiserFrameSize_nBins; 83 | 84 | switch(u16DigitiserType) 85 | { 86 | case WB_SPECTROMETER_LRPP: 87 | u32DigitiserFrameSize_nBins = 1024; 88 | break; 89 | 90 | case WB_SPECTROMETER_LRQU: 91 | u32DigitiserFrameSize_nBins = 1024; 92 | break; 93 | 94 | case NB_SPECTROMETER_LRPP: 95 | u32DigitiserFrameSize_nBins = 4096; 96 | break; 97 | 98 | case NB_SPECTROMETER_LRQU: 99 | u32DigitiserFrameSize_nBins = 4096; 100 | break; 101 | 102 | default: 103 | u32DigitiserFrameSize_nBins = 0; 104 | break; 105 | } 106 | 107 | return u32DigitiserFrameSize_nBins; 108 | } 109 | -------------------------------------------------------------------------------- /SpectrometerHeader.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | #include 4 | #include 5 | #include 6 | 7 | //Library includes 8 | 9 | //Local includes 10 | #include "SpectrometerHeader.h" 11 | #include "SpectrometerDefinitions.h" 12 | #include "../../AVNUtilLibs/Timestamp/Timestamp.h" 13 | #include "ByteSwap.h" //For old versions of GCC there are some byte swap functions missing 14 | 15 | cSpectrometerHeader::cSpectrometerHeader(const char* pcData) 16 | { 17 | deserialise(pcData); 18 | } 19 | 20 | cSpectrometerHeader::cSpectrometerHeader(const std::vector &vcData) 21 | { 22 | deserialise(vcData); 23 | } 24 | 25 | cSpectrometerHeader::cSpectrometerHeader(): 26 | m_u32SyncWord(0), 27 | m_i64tTimestamp_us(0), 28 | m_u8SubframeNumber(0), 29 | m_u8NSubframes(0), 30 | m_u16DigitiserType(0xffff), 31 | m_bNoiseDiodeOn(false), 32 | m_bFlipEndianess(true) //Assume true by default Roach is big endian, most PCs are little endian. 33 | { 34 | } 35 | 36 | cSpectrometerHeader::~cSpectrometerHeader() 37 | { 38 | } 39 | 40 | std::string cSpectrometerHeader::toString() 41 | { 42 | std::stringstream oSS; 43 | oSS << "Sync word: " << std::hex << m_u32SyncWord << std::dec << std::endl; 44 | oSS << "Timestamp: " << AVN::stringFromTimestamp_full(m_i64tTimestamp_us) << std::endl; 45 | oSS << "Subframe numer: " << (uint32_t)m_u8SubframeNumber << std::endl; 46 | oSS << "Number of subframes: " << (uint32_t)m_u8NSubframes << std::endl; 47 | oSS << "Digitiser type: " << m_u16DigitiserType << " (" << AVN::Spectrometer::digitiserTypeToString(m_u16DigitiserType) << ")" << std::endl; 48 | oSS << "Noise diode enabled: " << m_bNoiseDiodeOn << std::endl; 49 | 50 | return oSS.str(); 51 | } 52 | 53 | bool cSpectrometerHeader::deserialise(const char* pcData) 54 | { 55 | if(*(uint32_t*)pcData == AVN::Spectrometer::SYNC_WORD) 56 | { 57 | m_bFlipEndianess = false; 58 | } 59 | #ifdef _WIN32 60 | else if(_byteswap_ulong( *(uint32_t*)pcData ) == AVN::Spectrometer::SYNC_WORD) 61 | #else 62 | else if(__builtin_bswap32( *(uint32_t*)pcData ) == AVN::Spectrometer::SYNC_WORD) 63 | #endif 64 | { 65 | m_bFlipEndianess = true; 66 | } 67 | else 68 | { 69 | //SYNC Error 70 | m_bValid = false; 71 | 72 | std::cout << "cSpectrometerHeader::deserialise(): Warning got wrong magic no: " 73 | << std::hex << *(uint32_t*)pcData << ". Expected " << AVN::Spectrometer::SYNC_WORD << std::dec << std::endl; 74 | 75 | return false; 76 | } 77 | 78 | if(m_bFlipEndianess) 79 | { 80 | #ifdef _WIN32 81 | m_u32SyncWord = (uint32_t)( _byteswap_ulong( *(uint32_t*)(pcData) ) ); 82 | m_i64tTimestamp_us = (int64_t)( _byteswap_uint64( *(int64_t*)(pcData + 4) ) ); 83 | m_u8SubframeNumber = *(uint8_t*)(pcData + 12); 84 | m_u8NSubframes = *(uint8_t*)(pcData + 13); 85 | m_u16DigitiserType = 0x000F & (uint16_t)( _byteswap_ushort( *(uint16_t*)(pcData + 14) ) ); 86 | m_bNoiseDiodeOn = ( 0x8000 & (uint16_t)( _byteswap_ushort( *(uint16_t*)(pcData + 14) ) ) ) >> 15; 87 | #else 88 | m_u32SyncWord = (uint32_t)( __builtin_bswap32( *(uint32_t*)(pcData) ) ); 89 | m_i64tTimestamp_us = (int64_t)( __builtin_bswap64( *(int64_t*)(pcData + 4) ) ); 90 | m_u8SubframeNumber = *(uint8_t*)(pcData + 12); 91 | m_u8NSubframes = *(uint8_t*)(pcData + 13); 92 | m_u16DigitiserType = 0x000F & (uint16_t)( __builtin_bswap16( *(uint16_t*)(pcData + 14) ) ); 93 | m_bNoiseDiodeOn = ( 0x8000 & (uint16_t)(__builtin_bswap16( *(uint16_t*)(pcData + 14) ) ) ) >> 15; 94 | #endif 95 | } 96 | else 97 | { 98 | m_u32SyncWord = *(uint32_t*)(pcData); 99 | m_i64tTimestamp_us = *(int64_t*)(pcData + 4); 100 | m_u8SubframeNumber = *(uint8_t*)(pcData + 12); 101 | m_u8NSubframes = *(uint8_t*)(pcData + 13); 102 | m_u16DigitiserType = 0x0001 & *(uint16_t*)(pcData + 14); 103 | m_bNoiseDiodeOn = ( 0x8000 & *(uint16_t*)(pcData + 14) ) >> 15; 104 | } 105 | 106 | m_bValid = true; 107 | return true; 108 | } 109 | 110 | bool cSpectrometerHeader::deserialise(const std::vector &vcData) 111 | { 112 | //Here we can check for size 113 | if(vcData.size() < AVN::Spectrometer::HEADER_SIZE_B) 114 | { 115 | std::cout << "cSpectrometerHeader::deserialise() Error provided vector is shorter that AVN::Spectrometer head size of " << AVN::Spectrometer::HEADER_SIZE_B << " bytes" << std::endl; 116 | std::cout << "Got length: " << vcData.size() << " bytes. Returning." << std::endl; 117 | return false; 118 | 119 | //In future this should also throw an exception 120 | } 121 | 122 | return deserialise(&vcData.front()); 123 | } 124 | 125 | std::vector cSpectrometerHeader::serialise() 126 | { 127 | //TODO: Place holder. Implement on demand 128 | 129 | std::vector vcSerialisedHeader; 130 | return vcSerialisedHeader; 131 | } 132 | 133 | //Accessors 134 | uint32_t cSpectrometerHeader::getSyncWord() const 135 | { 136 | return m_u32SyncWord; 137 | } 138 | 139 | int64_t cSpectrometerHeader::getTimestamp_us() const 140 | { 141 | return m_i64tTimestamp_us; 142 | } 143 | 144 | uint8_t cSpectrometerHeader::getSubframeNumber() const 145 | { 146 | return m_u8SubframeNumber; 147 | } 148 | 149 | uint8_t cSpectrometerHeader::getNSubframes() const 150 | { 151 | return m_u8NSubframes; 152 | } 153 | 154 | uint16_t cSpectrometerHeader::getDigitiserType() const 155 | { 156 | return m_u16DigitiserType; 157 | } 158 | 159 | bool cSpectrometerHeader::getNoiseDiodeOn() const 160 | { 161 | return m_bNoiseDiodeOn; 162 | } 163 | 164 | //Mutators 165 | void cSpectrometerHeader::setSyncWord(uint32_t u32SyncWord) 166 | { 167 | m_u32SyncWord = u32SyncWord; 168 | } 169 | 170 | void cSpectrometerHeader::setTimestamp_us(int64_t i64Timestamp) 171 | { 172 | m_i64tTimestamp_us = i64Timestamp; 173 | } 174 | 175 | void cSpectrometerHeader::setSubframeNumber(uint8_t u8SubframeNumber) 176 | { 177 | m_u8SubframeNumber = u8SubframeNumber; 178 | } 179 | 180 | void cSpectrometerHeader::setNSubframes(uint8_t u8NSubframes) 181 | { 182 | m_u8NSubframes = u8NSubframes; 183 | } 184 | 185 | void cSpectrometerHeader::setDigitiserType(uint16_t u16DigitiserType) 186 | { 187 | m_u16DigitiserType = u16DigitiserType; 188 | } 189 | 190 | void cSpectrometerHeader::setNoiseDiodeOn(bool bNoiseDiodeOn) 191 | { 192 | m_bNoiseDiodeOn = bNoiseDiodeOn; 193 | } 194 | 195 | bool cSpectrometerHeader::requiresEndianessFlip() 196 | { 197 | return m_bFlipEndianess; 198 | } 199 | 200 | bool cSpectrometerHeader::isValid() 201 | { 202 | return m_bValid; 203 | } 204 | -------------------------------------------------------------------------------- /SpectrometerDataStreamInterpreter.h: -------------------------------------------------------------------------------- 1 | #ifndef SPECTROMETER_DATA_STREAM_INTERPRETER_H 2 | #define SPECTROMETER_DATA_STREAM_INTERPRETER_H 3 | 4 | //System includes 5 | #include 6 | #include 7 | 8 | #ifdef _WIN32 9 | #include 10 | 11 | #ifndef int64_t 12 | typedef __int64 int64_t; 13 | #endif 14 | 15 | #ifndef uint64_t 16 | typedef unsigned __int64 uint64_t; 17 | #endif 18 | 19 | #else 20 | #include 21 | #endif 22 | 23 | //Library includes 24 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 25 | #include 26 | #endif 27 | 28 | //Local includes 29 | #include "SpectrometerHeader.h" 30 | #include "../../AVNAppLibs/SocketStreamers/SocketReceiverBase.h" 31 | 32 | class cSpectrometerDataStreamInterpreter : public cSocketReceiverBase::cDataCallbackInterface 33 | { 34 | public: 35 | class cCallbackInterface 36 | { 37 | public: 38 | virtual void getNextFrame_callback(const std::vector &vi32Chan0, const std::vector &vi32Chan1, const std::vector &vi32Chan2, std::vector &vi32Chan3, 39 | const cSpectrometerHeader &oHeader) = 0; 40 | }; 41 | 42 | cSpectrometerDataStreamInterpreter(boost::shared_ptr pSocketReceiver); 43 | cSpectrometerDataStreamInterpreter(); 44 | ~cSpectrometerDataStreamInterpreter(); 45 | 46 | void setUpdateRate(uint32_t u32UpdateRate_ms); 47 | 48 | bool synchronise(); 49 | bool getNextFrame(float *pfChan0, float *pfChan1, float *pfChan2, float *pfChan3, uint32_t u32AllocateSize_nElements); 50 | bool getNextFrame(int32_t *pi32Chan0, int32_t *pi32Chan1, int32_t *pi32Chan2, int32_t *pi32Chan3, uint32_t u32AllocateSize_nElements); 51 | 52 | const cSpectrometerHeader &getLastHeader(); 53 | 54 | uint32_t getNValuesPerChannelPerFrame(); 55 | 56 | bool isRunning(); 57 | void setIsRunning(bool bIsRunning); 58 | 59 | void registerCallbackHandler(cCallbackInterface* pNewHandler); 60 | void registerCallbackHandler(boost::shared_ptr pNewHandler); 61 | void deregisterCallbackHandler(cCallbackInterface* pHandler); 62 | void deregisterCallbackHandler(boost::shared_ptr pHandler); 63 | 64 | virtual void offloadData_callback(char* pcData, uint32_t u32Size_B); 65 | 66 | protected: 67 | boost::shared_ptr m_pSocketReceiver; 68 | 69 | cSpectrometerHeader m_oCurrentHeader; 70 | cSpectrometerHeader m_oPreviousHeader; 71 | 72 | bool m_bIsRunning; 73 | 74 | boost::shared_mutex m_oMutex; 75 | 76 | //Update frame rate. Output a frame every so many milliseconds. 77 | //Results in some data being discarded. 0 (default) implies no discarding 78 | uint32_t m_u32UpdateRate_ms; 79 | 80 | //Variables and vectors used interpretting: 81 | vector m_vcPacket; 82 | 83 | uint32_t m_u32PacketSize_B; 84 | uint32_t m_u32NValuesPerFrame; 85 | uint32_t m_u32NValuesPerPacket; 86 | int64_t m_i64LastUsedTimestamp_us; 87 | uint8_t m_u8ExpectedSubframeIndex; 88 | 89 | bool m_bSkipFrame; 90 | 91 | //Variables used for callback function mode 92 | std::vector< std::vector > m_vviChannelData; 93 | 94 | int32_t *m_pi32Chan0; 95 | int32_t *m_pi32Chan1; 96 | int32_t *m_pi32Chan2; 97 | int32_t *m_pi32Chan3; 98 | 99 | bool m_bSynchronised; 100 | 101 | std::vector > m_vpCallbackHandlers_shared; 102 | std::vector m_vpCallbackHandlers; //For classes owning and instance of this class a regular pointer is simpler. 103 | boost::shared_mutex m_oCallbackHandlersMutex; 104 | 105 | 106 | //Inline functions 107 | inline bool headerConsistencyCheck() 108 | { 109 | //Some more consistency checks 110 | if(m_oCurrentHeader.getSubframeNumber() != m_u8ExpectedSubframeIndex) 111 | { 112 | std::cout << "Expected packet index " << (uint32_t)m_u8ExpectedSubframeIndex << ", got " << (uint32_t)m_oCurrentHeader.getSubframeNumber() << ". Resynchronising." << std::endl; 113 | return false; 114 | } 115 | 116 | if(m_oCurrentHeader.getNSubframes() != m_oPreviousHeader.getNSubframes()) 117 | { 118 | std::cout << "Expected " << m_oPreviousHeader.getNSubframes() << " packets per frame, got " << (uint32_t)m_oCurrentHeader.getNSubframes() << ". Resynchronising." << std::endl; 119 | return false; 120 | } 121 | 122 | if(m_oCurrentHeader.getDigitiserType() != m_oPreviousHeader.getDigitiserType()) 123 | { 124 | std::cout << "Expected plot type " << m_oPreviousHeader.getDigitiserType() << " , got " << m_oCurrentHeader.getDigitiserType() << ". Resynchronising." << std::endl; 125 | return false; 126 | } 127 | 128 | m_oPreviousHeader = m_oCurrentHeader; 129 | 130 | return true; 131 | } 132 | 133 | inline void deinterleaveInt32ToInt32(int32_t* pi32Data, int32_t *&pi32Chan0, int32_t *&pi32Chan1, int32_t *&pi32Chan2, int32_t *&pi32Chan3, uint32_t u32NValuesPerChan, bool bFlipEndianess) 134 | { 135 | if(bFlipEndianess) 136 | { 137 | for(uint32_t u32ValueNo = 0; u32ValueNo < u32NValuesPerChan; u32ValueNo++) 138 | { 139 | #ifdef _WIN32 140 | *pi32Chan0++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 141 | *pi32Chan1++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 142 | *pi32Chan2++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 143 | *pi32Chan3++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 144 | #else 145 | *pi32Chan0++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 146 | *pi32Chan1++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 147 | *pi32Chan2++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 148 | *pi32Chan3++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 149 | #endif 150 | } 151 | } 152 | else 153 | { 154 | for(uint32_t u32ValueNo = 0; u32ValueNo < u32NValuesPerChan; u32ValueNo++) 155 | { 156 | *pi32Chan0++ = (int32_t)( *pi32Data++ ); 157 | *pi32Chan1++ = (int32_t)( *pi32Data++ ); 158 | *pi32Chan2++ = (int32_t)( *pi32Data++ ); 159 | *pi32Chan3++ = (int32_t)( *pi32Data++ ); 160 | } 161 | } 162 | } 163 | 164 | inline void deinterleaveInt32ToFloat(int32_t* pi32Data, float *&pfChan0, float *&pfChan1, float *&pfChan2, float *&pfChan3, uint32_t u32NValuesPerChan, bool bFlipEndianess) 165 | { 166 | if(bFlipEndianess) 167 | { 168 | for(uint32_t u32ValueNo = 0; u32ValueNo < u32NValuesPerChan; u32ValueNo++) 169 | { 170 | #ifdef _WIN32 171 | *pfChan0++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 172 | *pfChan1++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 173 | *pfChan2++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 174 | *pfChan3++ = (int32_t)( _byteswap_ulong( *pi32Data++ ) ); 175 | #else 176 | *pfChan0++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 177 | *pfChan1++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 178 | *pfChan2++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 179 | *pfChan3++ = (int32_t)( __builtin_bswap32( *pi32Data++ ) ); 180 | #endif 181 | } 182 | } 183 | else 184 | { 185 | for(uint32_t u32ValueNo = 0; u32ValueNo < u32NValuesPerChan; u32ValueNo++) 186 | { 187 | *pfChan0++ = (int32_t)( *pi32Data++ ); 188 | *pfChan1++ = (int32_t)( *pi32Data++ ); 189 | *pfChan2++ = (int32_t)( *pi32Data++ ); 190 | *pfChan3++ = (int32_t)( *pi32Data++ ); 191 | } 192 | } 193 | } 194 | }; 195 | 196 | #endif // SPECTROMETER_DATA_STREAM_INTERPRETER_H 197 | -------------------------------------------------------------------------------- /SpectrometerDataStreamInterpreter.cpp: -------------------------------------------------------------------------------- 1 | //System includes 2 | 3 | //Library includes 4 | 5 | //Local includes 6 | #include "SpectrometerDataStreamInterpreter.h" 7 | 8 | using namespace std; 9 | 10 | cSpectrometerDataStreamInterpreter::cSpectrometerDataStreamInterpreter(boost::shared_ptr pSocketReceiver) : 11 | m_pSocketReceiver(pSocketReceiver), 12 | m_bIsRunning(true), 13 | m_u32UpdateRate_ms(0), 14 | m_u32PacketSize_B(0), 15 | m_u32NValuesPerFrame(0), 16 | m_u32NValuesPerPacket(0), 17 | m_i64LastUsedTimestamp_us(0), 18 | m_bSkipFrame(false), 19 | m_vviChannelData(4), 20 | m_bSynchronised(false) 21 | { 22 | } 23 | 24 | cSpectrometerDataStreamInterpreter::cSpectrometerDataStreamInterpreter() : 25 | m_bIsRunning(true), 26 | m_u32UpdateRate_ms(0), 27 | m_u32PacketSize_B(0), 28 | m_u32NValuesPerFrame(0), 29 | m_u32NValuesPerPacket(0), 30 | m_i64LastUsedTimestamp_us(0), 31 | m_bSkipFrame(false), 32 | m_vviChannelData(4), 33 | m_bSynchronised(false) 34 | { 35 | m_pSocketReceiver.reset(); //Not used 36 | } 37 | 38 | cSpectrometerDataStreamInterpreter::~cSpectrometerDataStreamInterpreter() 39 | { 40 | setIsRunning(false); 41 | } 42 | 43 | void cSpectrometerDataStreamInterpreter::setUpdateRate(uint32_t u32UpdateRate_ms) 44 | { 45 | //Thread safe mutator 46 | boost::unique_lock oLock(m_oMutex); 47 | 48 | m_u32UpdateRate_ms = u32UpdateRate_ms; 49 | } 50 | 51 | bool cSpectrometerDataStreamInterpreter::isRunning() 52 | { 53 | //Thread safe accessor 54 | boost::shared_lock oLock(m_oMutex); 55 | 56 | return m_bIsRunning; 57 | } 58 | 59 | void cSpectrometerDataStreamInterpreter::setIsRunning(bool bIsRunning) 60 | { 61 | //Thread safe flag mutator 62 | boost::unique_lock oLock(m_oMutex); 63 | 64 | m_bIsRunning = bIsRunning; 65 | } 66 | 67 | bool cSpectrometerDataStreamInterpreter::synchronise() 68 | { 69 | setIsRunning(true); 70 | 71 | int32_t i32NextPacketSize_B = 0; 72 | 73 | do 74 | { 75 | if(!isRunning()) 76 | return false; 77 | 78 | i32NextPacketSize_B = m_pSocketReceiver->getNextPacketSize_B(500); 79 | } 80 | while(i32NextPacketSize_B == -1); 81 | 82 | //Resize array as required 83 | if(m_vcPacket.size() != (uint32_t)i32NextPacketSize_B) 84 | { 85 | m_vcPacket.resize(i32NextPacketSize_B); 86 | m_u32PacketSize_B = i32NextPacketSize_B; 87 | } 88 | 89 | //Synchronise: Find the last packet of the frame 90 | cout << "cSpectrometerDataStreamInterpreter::synchronise(): Resynchronising to frame border." << endl; 91 | do 92 | { 93 | if(!isRunning()) 94 | return false; 95 | 96 | m_pSocketReceiver->getNextPacket(&m_vcPacket.front(), 500); 97 | 98 | //Check that we synced to the stream correctly 99 | if(!m_oCurrentHeader.deserialise(m_vcPacket)) 100 | { 101 | cout << "cSpectrometerDataStreamInterpreter::synchronise(): Deserialising header failed, resynchronising." << endl; 102 | 103 | return false; 104 | } 105 | 106 | cout << "cSpectrometerDataStreamInterpreter::synchronise(): Synchronising: Got packet " << (uint32_t)m_oCurrentHeader.getSubframeNumber() 107 | << " of " << (uint32_t)m_oCurrentHeader.getNSubframes() << endl; 108 | } 109 | //Keep going until the next subframe will be subframe #0 110 | while(m_oCurrentHeader.getSubframeNumber() != m_oCurrentHeader.getNSubframes() - 1); 111 | 112 | cout << "cSpectrometerDataStreamInterpreter::synchronise(): Synchronisation successful." << endl; 113 | 114 | m_u32NValuesPerPacket = (i32NextPacketSize_B - AVN::Spectrometer::HEADER_SIZE_B) / sizeof(int32_t); 115 | m_u32NValuesPerFrame = m_u32NValuesPerPacket * m_oCurrentHeader.getNSubframes(); 116 | 117 | //Store current header 118 | m_oPreviousHeader = m_oCurrentHeader; 119 | 120 | return true; 121 | } 122 | 123 | bool cSpectrometerDataStreamInterpreter::getNextFrame(int32_t *pi32Chan0, int32_t *pi32Chan1, int32_t *pi32Chan2, int32_t *pi32Chan3, uint32_t u32AllocateSize_nElements) 124 | { 125 | setIsRunning(true); 126 | 127 | int32_t *pi32Data = NULL; 128 | int32_t i32NextPacketSize_B = 0; 129 | 130 | //Check plot vectors sizes 131 | //4 channels of data (L,R,Q,U or I0, Q0, I1, Q1) 132 | //There number of samples per channel is total values per frame / 4 133 | if(u32AllocateSize_nElements != m_u32NValuesPerFrame / 4) 134 | { 135 | return false; 136 | } 137 | 138 | //Read the data 139 | 140 | for(m_u8ExpectedSubframeIndex = 0; m_u8ExpectedSubframeIndex < m_oCurrentHeader.getNSubframes(); m_u8ExpectedSubframeIndex++) 141 | { 142 | 143 | do 144 | { 145 | if(!isRunning()) 146 | return false; 147 | 148 | i32NextPacketSize_B = m_pSocketReceiver->getNextPacketSize_B(500); 149 | } 150 | while(i32NextPacketSize_B == -1); 151 | 152 | if((unsigned)i32NextPacketSize_B != m_u32PacketSize_B) 153 | { 154 | cout << "cSpectrometerDataStreamInterpreter::getNextFrame(): Got different packet size, resynchronising." << endl; 155 | return false; 156 | } 157 | 158 | //Read the next packet 159 | while(!m_pSocketReceiver->getNextPacket(&m_vcPacket.front(), 500)) 160 | { 161 | if(!isRunning()) 162 | return false; 163 | } 164 | 165 | //Check for data consistency 166 | if(!headerConsistencyCheck()) 167 | return false; 168 | 169 | if(!m_oCurrentHeader.deserialise(m_vcPacket)) 170 | { 171 | cout << "cSpectrometerDataStreamInterpreter::getNextFrame(): Deserialising header failed, resynchronising." << endl; 172 | return false; 173 | } 174 | 175 | 176 | //Get timestamp on the first subframe 177 | if(!m_u8ExpectedSubframeIndex) 178 | { 179 | //Attempt to reach 30 frames per second. 180 | boost::upgrade_lock oLock(m_oMutex); //For for update rate variable 181 | 182 | m_bSkipFrame = (m_oCurrentHeader.getTimestamp_us() - m_i64LastUsedTimestamp_us) < m_u32UpdateRate_ms * 1000; 183 | } 184 | 185 | if(m_bSkipFrame) 186 | { 187 | continue; 188 | } 189 | 190 | pi32Data = (int32_t*)((char*)(&m_vcPacket.front()) + AVN::Spectrometer::HEADER_SIZE_B); //Go to offset of first sample (header is 16 bytes). 191 | 192 | //Deinterleave data to output channels of type float 193 | deinterleaveInt32ToInt32(pi32Data, pi32Chan0, pi32Chan1, pi32Chan2, pi32Chan3, m_u32NValuesPerPacket / 4, m_oCurrentHeader.requiresEndianessFlip()); 194 | } 195 | 196 | if(!m_bSkipFrame) 197 | { 198 | m_i64LastUsedTimestamp_us = m_oCurrentHeader.getTimestamp_us(); 199 | } 200 | 201 | return true; 202 | } 203 | 204 | bool cSpectrometerDataStreamInterpreter::getNextFrame(float *pfChan0, float *pfChan1, float *pfChan2, float *pfChan3, uint32_t u32AllocateSize_nElements) 205 | { 206 | setIsRunning(true); 207 | 208 | int32_t *pi32Data = NULL; 209 | int32_t i32NextPacketSize_B = 0; 210 | 211 | //Check plot vectors sizes 212 | //4 channels of data (L,R,Q,U or I0, Q0, I1, Q1) 213 | //There number of samples per channel is total values per frame / 4 214 | if(u32AllocateSize_nElements != m_u32NValuesPerFrame / 4) 215 | { 216 | return false; 217 | } 218 | 219 | //Read the data 220 | 221 | for(m_u8ExpectedSubframeIndex = 0; m_u8ExpectedSubframeIndex < m_oCurrentHeader.getNSubframes(); m_u8ExpectedSubframeIndex++) 222 | { 223 | 224 | do 225 | { 226 | if(!isRunning()) 227 | return false; 228 | 229 | i32NextPacketSize_B = m_pSocketReceiver->getNextPacketSize_B(500); 230 | } 231 | while(i32NextPacketSize_B == -1); 232 | 233 | if((unsigned)i32NextPacketSize_B != m_u32PacketSize_B) 234 | { 235 | cout << "cSpectrometerDataStreamInterpreter::getNextFrame(): Got different packet size, resynchronising." << endl; 236 | return false; 237 | } 238 | 239 | //Read the next packet 240 | while(!m_pSocketReceiver->getNextPacket(&m_vcPacket.front(), 500)) 241 | { 242 | if(!isRunning()) 243 | return false; 244 | } 245 | 246 | if(!m_oCurrentHeader.deserialise(m_vcPacket)) 247 | { 248 | cout << "cSpectrometerDataStreamInterpreter::getNextFrame(): Deserialising header failed, resynchronising." << endl; 249 | return false; 250 | } 251 | 252 | //Check for data consistency 253 | if(!headerConsistencyCheck()) 254 | return false; 255 | 256 | //Get timestamp on the first subframe 257 | if(!m_u8ExpectedSubframeIndex) 258 | { 259 | //Attempt to reach 30 frames per second. 260 | boost::upgrade_lock oLock(m_oMutex); //For for update rate variable 261 | 262 | m_bSkipFrame = (m_oCurrentHeader.getTimestamp_us() - m_i64LastUsedTimestamp_us) < m_u32UpdateRate_ms * 1000; 263 | } 264 | 265 | if(m_bSkipFrame) 266 | { 267 | continue; 268 | } 269 | 270 | 271 | pi32Data = (int32_t*)((char*)(&m_vcPacket.front()) + AVN::Spectrometer::HEADER_SIZE_B); //Go to offset of first sample (header is 16 bytes). (NB: Note cast to char before adding bytes to pointer.) 272 | 273 | //Deinterleave data to output channels of type float 274 | deinterleaveInt32ToFloat(pi32Data, pfChan0, pfChan1, pfChan2, pfChan3, m_u32NValuesPerPacket / 4, m_oCurrentHeader.requiresEndianessFlip()); 275 | } 276 | 277 | if(!m_bSkipFrame) 278 | { 279 | m_i64LastUsedTimestamp_us = m_oCurrentHeader.getTimestamp_us(); 280 | } 281 | 282 | return true; 283 | } 284 | 285 | const cSpectrometerHeader &cSpectrometerDataStreamInterpreter::getLastHeader() 286 | { 287 | return m_oCurrentHeader; 288 | } 289 | 290 | uint32_t cSpectrometerDataStreamInterpreter::getNValuesPerChannelPerFrame() 291 | { 292 | return m_u32NValuesPerFrame / 4; 293 | } 294 | 295 | void cSpectrometerDataStreamInterpreter::offloadData_callback(char* pcData, uint32_t u32Size_B) 296 | { 297 | int32_t *pi32Data = NULL; 298 | 299 | if(!m_bSynchronised) 300 | { 301 | //Synchronise: Find the last packet of the frame 302 | 303 | if(!isRunning()) 304 | return; 305 | 306 | //Check that data is large enough for at least the header 307 | if(u32Size_B < AVN::Spectrometer::HEADER_SIZE_B) 308 | { 309 | cout << "cSpectrometerDataStreamInterpreter::offloadData_callback(): Warning got packet size of " << u32Size_B << "which is smaller than AVN spectrometer header size." << endl; 310 | return; 311 | } 312 | 313 | //Check that we synced to the stream correctly 314 | if(!m_oCurrentHeader.deserialise(pcData)) 315 | { 316 | cout << "cSpectrometerDataStreamInterpreter::offloadData_callback(): Deserialising header failed, attempting resynchronising." << endl; 317 | return; 318 | } 319 | 320 | cout << "cSpectrometerDataStreamInterpreter::offloadData_callback(): Synchronising: Got packet " << (uint32_t)m_oCurrentHeader.getSubframeNumber() 321 | << " of " << (uint32_t)m_oCurrentHeader.getNSubframes() << endl; 322 | 323 | if(m_oCurrentHeader.getSubframeNumber() == m_oCurrentHeader.getNSubframes() - 1) 324 | { 325 | cout << "cSpectrometerDataStreamInterpreter::offloadData_callback(): Synchronisation successful." << endl; 326 | 327 | m_u32NValuesPerPacket = (u32Size_B - AVN::Spectrometer::HEADER_SIZE_B) / sizeof(int32_t); 328 | m_u32NValuesPerFrame = m_u32NValuesPerPacket * m_oCurrentHeader.getNSubframes(); 329 | m_u32PacketSize_B = u32Size_B; 330 | 331 | //Store current header 332 | m_oPreviousHeader = m_oCurrentHeader; 333 | 334 | m_bSynchronised = true; 335 | 336 | //Resize channel vectors as necessary 337 | if((uint32_t)m_vviChannelData[0].size() != m_u32NValuesPerFrame / 4) 338 | { 339 | for(uint32_t ui = 0; ui < m_vviChannelData.size(); ui++) 340 | { 341 | m_vviChannelData[ui].resize(m_u32NValuesPerFrame / 4); 342 | } 343 | } 344 | 345 | m_u8ExpectedSubframeIndex = 0; 346 | 347 | //The next packet should then be first in the next frame 348 | } 349 | 350 | return; 351 | } 352 | 353 | //Check packet size 354 | if(u32Size_B != m_u32PacketSize_B) 355 | { 356 | cout << "cSpectrometerDataStreamInterpreter::offloadData_callback(): Got different packet size, resynchronising." << endl; 357 | m_bSynchronised = false; 358 | return; 359 | } 360 | 361 | //Unpack and check this frames header 362 | if(!m_oCurrentHeader.deserialise(pcData)) 363 | { 364 | cout << "cSpectrometerDataStreamInterpreter::offloadData_callback(): Deserialising header failed, attempting resynchronising." << endl; 365 | 366 | m_bSynchronised = false; 367 | return; 368 | } 369 | 370 | //Check for data consistency 371 | if(!headerConsistencyCheck()) 372 | { 373 | m_bSynchronised = false; 374 | return; 375 | } 376 | 377 | //Get timestamp on the first subframe 378 | if(!m_u8ExpectedSubframeIndex) 379 | { 380 | //Attempt to reach 30 frames per second. 381 | boost::upgrade_lock oLock(m_oMutex); //For for update rate variable 382 | 383 | m_bSkipFrame = (m_oCurrentHeader.getTimestamp_us() - m_i64LastUsedTimestamp_us) < m_u32UpdateRate_ms * 1000; 384 | 385 | //Also the the pointers to the beginning of the deinterleaved channel data 386 | m_pi32Chan0 = &(m_vviChannelData[0].front()); 387 | m_pi32Chan1 = &(m_vviChannelData[1].front()); 388 | m_pi32Chan2 = &(m_vviChannelData[2].front()); 389 | m_pi32Chan3 = &(m_vviChannelData[3].front()); 390 | } 391 | 392 | m_u8ExpectedSubframeIndex++; 393 | 394 | if(m_bSkipFrame) 395 | { 396 | return; 397 | } 398 | 399 | pi32Data = (int32_t*)(pcData + AVN::Spectrometer::HEADER_SIZE_B); //Go to offset of first sample (header is 16 bytes). 400 | 401 | //Deinterleave data to output channels of type float 402 | deinterleaveInt32ToInt32(pi32Data, m_pi32Chan0, m_pi32Chan1, m_pi32Chan2, m_pi32Chan3, m_u32NValuesPerPacket / 4, m_oCurrentHeader.requiresEndianessFlip()); 403 | 404 | m_i64LastUsedTimestamp_us = m_oCurrentHeader.getTimestamp_us(); 405 | 406 | //If all data has been received for this data frame pass on to the callback handler(s) 407 | if(m_oCurrentHeader.getSubframeNumber() == m_oCurrentHeader.getNSubframes() - 1) 408 | { 409 | boost::shared_lock oLock(m_oCallbackHandlersMutex); 410 | for(uint32_t ui = 0; ui < m_vpCallbackHandlers.size(); ui++) 411 | { 412 | m_vpCallbackHandlers[ui]->getNextFrame_callback(m_vviChannelData[0], m_vviChannelData[1], m_vviChannelData[2], m_vviChannelData[3], m_oCurrentHeader); 413 | } 414 | 415 | for(uint32_t ui = 0; ui < m_vpCallbackHandlers_shared.size(); ui++) 416 | { 417 | m_vpCallbackHandlers_shared[ui]->getNextFrame_callback(m_vviChannelData[0], m_vviChannelData[1], m_vviChannelData[2], m_vviChannelData[3], m_oCurrentHeader); 418 | } 419 | 420 | //The next subframe will then be the first of the new complete data frame 421 | m_u8ExpectedSubframeIndex = 0; 422 | } 423 | } 424 | 425 | void cSpectrometerDataStreamInterpreter::registerCallbackHandler(boost::shared_ptr pNewHandler) 426 | { 427 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 428 | 429 | m_vpCallbackHandlers_shared.push_back(pNewHandler); 430 | 431 | cout << "cSpectrometerDataStreamInterpreter::registerCallbackHandler(): Successfully registered callback handler: " << pNewHandler.get() << endl; 432 | } 433 | 434 | void cSpectrometerDataStreamInterpreter::registerCallbackHandler(cCallbackInterface* pNewHandler) 435 | { 436 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 437 | 438 | m_vpCallbackHandlers.push_back(pNewHandler); 439 | 440 | cout << "cSpectrometerDataStreamInterpreter::registerCallbackHandler(): Successfully registered callback handler: " << pNewHandler << endl; 441 | } 442 | 443 | void cSpectrometerDataStreamInterpreter::deregisterCallbackHandler(cCallbackInterface* pHandler) 444 | { 445 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 446 | bool bSuccess = false; 447 | 448 | //Search for matching pointer values and erase 449 | for(uint32_t ui = 0; ui < m_vpCallbackHandlers.size();) 450 | { 451 | if(m_vpCallbackHandlers[ui] == pHandler) 452 | { 453 | m_vpCallbackHandlers.erase(m_vpCallbackHandlers.begin() + ui); 454 | 455 | cout << "cSpectrometerDataStreamInterpreter::deregisterCallbackHandler(): Deregistered callback handler: " << pHandler << endl; 456 | bSuccess = true; 457 | } 458 | else 459 | { 460 | ui++; 461 | } 462 | } 463 | 464 | if(!bSuccess) 465 | { 466 | cout << "cSpectrometerDataStreamInterpreter::deregisterCallbackHandler(): Warning: Deregistering callback handler: " << pHandler << " failed. Object instance not found." << endl; 467 | } 468 | } 469 | 470 | void cSpectrometerDataStreamInterpreter::deregisterCallbackHandler(boost::shared_ptr pHandler) 471 | { 472 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 473 | bool bSuccess = false; 474 | 475 | //Search for matching pointer values and erase 476 | for(uint32_t ui = 0; ui < m_vpCallbackHandlers_shared.size();) 477 | { 478 | if(m_vpCallbackHandlers_shared[ui].get() == pHandler.get()) 479 | { 480 | m_vpCallbackHandlers_shared.erase(m_vpCallbackHandlers_shared.begin() + ui); 481 | 482 | cout << "cSpectrometerDataStreamInterpreter::deregisterCallbackHandler(): Deregistered callback handler: " << pHandler.get() << endl; 483 | bSuccess = true; 484 | } 485 | else 486 | { 487 | ui++; 488 | } 489 | } 490 | 491 | if(!bSuccess) 492 | { 493 | cout << "cSpectrometerDataStreamInterpreter::deregisterCallbackHandler(): Warning: Deregistering callback handler: " << pHandler.get() << " failed. Object instance not found." << endl; 494 | } 495 | } 496 | -------------------------------------------------------------------------------- /SpectrometerHDF5OutputFile.h: -------------------------------------------------------------------------------- 1 | #ifndef SPECTROMETER_HDF5_OUTPUT_FILE_H 2 | #define SPECTROMETER_HDF5_OUTPUT_FILE_H 3 | 4 | //System includes 5 | #include 6 | #include 7 | 8 | #ifdef _WIN32 9 | #include 10 | 11 | #ifndef int64_t 12 | typedef __int64 int64_t; 13 | #endif 14 | 15 | #ifndef uint64_t 16 | typedef unsigned __int64 uint64_t; 17 | #endif 18 | 19 | #else 20 | #include 21 | #endif 22 | 23 | #include 24 | 25 | //Library includes 26 | extern "C" { 27 | #include 28 | } 29 | 30 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 31 | #include 32 | #endif 33 | 34 | 35 | //Local includes 36 | #include "SpectrometerHeader.h" 37 | #include "SpectrometerDefinitions.h" 38 | 39 | class cSpectrometerHDF5OutputFile 40 | { 41 | //Structures used for storing entries in HDF5 tables (NB: these must consist of POD! http://www.cplusplus.com/reference/type_traits/is_pod/) 42 | 43 | //Specific structures 44 | typedef struct cMarkupLabels 45 | { 46 | double m_dTimestamp_s; 47 | char m_chaLabel[64]; 48 | } cMarkupLabels; 49 | 50 | typedef struct cTimestampedChar 51 | { 52 | double m_dTimestamp_s; 53 | char m_chaValue[1]; 54 | char m_chaStatus[7]; 55 | } cTimestampedChar; 56 | 57 | typedef struct cSourceSelection 58 | { 59 | double m_dTimestamp_s; 60 | char m_chaSource[64]; 61 | char m_chaStatus[7]; 62 | } cSourceSelection; 63 | 64 | typedef struct cAntennaStatus 65 | { 66 | double m_dTimestamp_s; 67 | char m_chaAntennaStatus[16]; 68 | char m_chaStatus[7]; 69 | } cAntennaStatus; 70 | 71 | typedef struct cNoiseDiodeSource 72 | { 73 | double m_dTimestamp_s; 74 | char m_chaSource[8]; 75 | char m_chaStatus[7]; 76 | } cNoiseDiodeSource; 77 | 78 | //General structures 79 | typedef struct cTimestampedInt 80 | { 81 | double m_dTimestamp_s; 82 | int32_t m_i32Value; 83 | char m_chaStatus[7]; 84 | } cTimestampedInt; 85 | 86 | typedef struct cTimestampedUnsignedInt 87 | { 88 | double m_dTimestamp_s; 89 | uint32_t m_u32Value; 90 | char m_chaStatus[7]; 91 | } cTimestampedUnsignedInt; 92 | 93 | typedef struct cTimestampedDouble 94 | { 95 | double m_dTimestamp_s; 96 | double m_dValue; 97 | char m_chaStatus[7]; 98 | } cTimestampedDouble; 99 | 100 | typedef struct cTimestampedDualDouble 101 | { 102 | double m_dTimestamp_s; 103 | double m_dValue1; 104 | double m_dValue2; 105 | char m_chaStatus[7]; 106 | } cTimestampedDualDouble; 107 | 108 | typedef struct cAntennaConfiguration 109 | { 110 | char m_chaAntennaName[64]; 111 | char m_chaAntennaDiameter_m[8]; 112 | char m_chaAntennaBeamwidth[8]; 113 | char m_chaAntennaLongitude_deg[16]; 114 | char m_chaAntennaLatitude_deg[16]; 115 | char m_chaAntennaAltitude_m[8]; 116 | char m_chaPointModelName[16]; //TODO: Remove this, I don't think it's necessary at all. 117 | } cAntennaConfiguration; 118 | 119 | 120 | public: 121 | cSpectrometerHDF5OutputFile(const std::string &strFilename, AVN::Spectrometer::digitiserType eDigitiserType, uint32_t u32NFrequencyBins); 122 | ~cSpectrometerHDF5OutputFile(); 123 | 124 | //Different functions can be called concurrently but any single function is not at present thread safe with regard to concurrent calls 125 | void addFrame(const std::vector &vi32Chan0, const std::vector &vi32Chan1, const std::vector &vi32Chan2, std::vector &vi32Chan3, 126 | const cSpectrometerHeader &oHeader); 127 | 128 | void addMarkupLabel(int64_t i64Timestamp_us, const std::string &strLabel); 129 | 130 | void addRequestedAntennaAz(int64_t i64Timestamp_us, double dAzimuth_deg, const std::string &strStatus); 131 | void addRequestedAntennaEl(int64_t i64Timestamp_us, double dElevation_deg, const std::string &strStatus); 132 | void addActualAntennaAz(int64_t i64Timestamp_us, double dAzimuth_deg, const std::string &strStatus); 133 | void addActualAntennaEl(int64_t i64Timestamp_us, double dElevation_deg, const std::string &strStatus); 134 | void addActualSourceOffsetAz(int64_t i64Timestamp_us, double dAzimuthOffset_deg, const std::string &strStatus); 135 | void addActualSourceOffsetEl(int64_t i64Timestamp_us, double dElevationOffset_deg, const std::string &strStatus); 136 | void addActualAntennaRA(int64_t i64Timestamp_us, double dRighAscension_deg, const std::string &strStatus); 137 | void addActualAntennaDec(int64_t i64Timestamp_us, double dDeclination_deg, const std::string &strStatus); 138 | 139 | void addAntennaStatus(int64_t i64Timestamp_us, const std::string &strAntennaStatus, const std::string &strStatus); 140 | void motorTorqueAzMaster(int64_t i64Timestamp_us, double dAzMaster_mNm, const std::string &strStatus); 141 | void motorTorqueAzSlave(int64_t i64Timestamp_us, double dAzSlave_mNm, const std::string &strStatus); 142 | void motorTorqueElMaster(int64_t i64Timestamp_us, double dElMaster_mNm, const std::string &strStatus); 143 | void motorTorqueElSlave(int64_t i64Timestamp_us, double dElSlave_mNm, const std::string &strStatus); 144 | 145 | void addNoiseDiodeSoftwareState(int64_t i64Timestamp_us, int32_t i32NoiseDiodeState, const std::string &strStatus); 146 | void addNoiseDiodeSource(int64_t i64Timestamp_us, const std::string &strNoiseSource, const std::string &strStatus); 147 | void addNoiseDiodeCurrent(int64_t i64Timestamp_us, double dNoiseDiodeCurrent_A, const std::string &strStatus); 148 | 149 | void addSourceSelection(int64_t i64Timestamp_us, const std::string &strSourceName, double dRighAscension_deg, double dDeclination_deg); 150 | 151 | void addFrequencySelectLCP(int64_t i64Timestamp_us, bool bFrequencySelectLCP, const std::string &strStatus); 152 | void addFrequencySelectRCP(int64_t i64Timestamp_us, bool bFrequencySelectRCP, const std::string &strStatus); 153 | void addFrequencyLO0Chan0(int64_t i64Timestamp_us, double dFrequencyLO0Chan0_Hz, const std::string &strStatus); 154 | void addFrequencyLO0Chan1(int64_t i64Timestamp_us, double dFrequencyLO0Chan1_MHz, const std::string &strStatus); 155 | void addFrequencyLO1(int64_t i64Timestamp_us, double dFrequencyLO1_MHz, const std::string &strStatus); 156 | void addReceiverBandwidthChan0(int64_t i64Timestamp_us, double dReceiverBandwidthChan0_MHz, const std::string &strStatus); 157 | void addReceiverBandwidthChan1(int64_t i64Timestamp_us, double dReceiverBandwidthChan1_MHz, const std::string &strStatus); 158 | 159 | void addAccumulationLength(int64_t i64Timestamp_us, uint32_t u32NFrames); 160 | void addCoarseChannelSelect(int64_t i64Timestamp_us, uint32_t u32ChannelNo); 161 | void setFrequencyFs(double dFrequencyFs_Hz); 162 | void setSizeOfCoarseFFT(uint32_t u32SizeOfCoarseFFT_nSamp); 163 | void setSizeOfFineFFT(uint32_t u32SizeOfFineFFT_nSamp); 164 | void addCoarseFFTShiftMask(int64_t i64Timestamp_us, uint32_t u32ShiftMask); 165 | void addAttenuationADCChan0(int64_t i64Timestamp_us, double dADCAttenuationChan0_dB); 166 | void addAttenuationADCChan1(int64_t i64Timestamp_us, double dADCAttenuationChan1_dB); 167 | 168 | void setAntennaName(const std::string &strAntennaName); 169 | void setAntennaBeamwidth(const std::string &strAntennaBeamwidth_deg); 170 | void setAntennaDiameter(const std::string &strAntennaDiameter_m); 171 | void setAntennaLatitude(const std::string &strAntennaLatitude_deg); 172 | void setAntennaAltitude(const std::string &strAntennaAltitude_m); 173 | void setAntennaLongitude(const std::string &strAntennaLongitude_deg); 174 | 175 | void setAntennaDelayModel(const std::vector &vdDelayModelParams); 176 | void setAppliedPointingModel(const std::string &strModelName, const std::vector &vdPointingModelParams); 177 | 178 | 179 | std::string getFilename() const; 180 | 181 | private: 182 | std::string m_strFilename; 183 | AVN::Spectrometer::digitiserType m_eDigitiserType; 184 | uint32_t m_u32NFrequencyBins; 185 | 186 | //HDF5: 187 | hid_t m_iH5FileHandle; 188 | hid_t m_iH5FileProperties; 189 | 190 | hid_t m_iH5DataGroupHandle; 191 | hid_t m_iH5MetaDataGroupHandle; 192 | hid_t m_iH5MarkupGroupHandle; 193 | hid_t m_iH5SensorsGroupHandle; 194 | hid_t m_iH5SensorsAntennasGroupHandle; 195 | hid_t m_iH5SensorsRFEGroupHandle; 196 | hid_t m_iH5SensorsDBEGroupHandle; 197 | hid_t m_iH5SensorsAntennasAntenna1GroupHandle; 198 | hid_t m_iH5ConfigurationGroupHandle; 199 | hid_t m_iH5ConfigurationAntennasGroupHandle; 200 | hid_t m_iH5ConfigurationAntennasAntenna1GroupHandle; 201 | hid_t m_iH5ConfigurationObservationGroupHandle; 202 | hid_t m_iH5ConfigurationDBEGroupHandle; 203 | 204 | hid_t m_iH5DatasetVis; 205 | hid_t m_iH5DatasetStokes; 206 | 207 | hsize_t m_aChannelDatasetDims[3]; 208 | hsize_t m_aChannelDatasetExtensionDims[3]; 209 | hsize_t m_aChannelDataOffset[3]; 210 | hsize_t m_aMemspaceSize[3]; 211 | 212 | //Values received / calculated from ROACH sample data stream 213 | std::vector m_vdSampleDataTimestamps_s; 214 | std::vector > m_vvfChannelAverages; 215 | std::vector m_voROACHNoiseDiodeStateChanges; 216 | 217 | //Values received from station controller 218 | std::vector m_voMarkupLabels; 219 | 220 | std::vector m_voRequestedAntennaAzs_deg; 221 | std::vector m_voRequestedAntennaEls_deg; 222 | std::vector m_voActualAntennaAzs_deg; 223 | std::vector m_voActualAntennaEls_deg; 224 | std::vector m_voActualSourceOffsetAzs_deg; 225 | std::vector m_voActualSourceOffsetEls_deg; 226 | std::vector m_voActualAntennaRAs_deg; 227 | std::vector m_voActualAntennaDecs_deg; 228 | 229 | std::vector m_voAntennaStatuses; 230 | std::vector m_voMotorTorquesAzMaster_mNm; 231 | std::vector m_voMotorTorquesAzSlave_mNm; 232 | std::vector m_voMotorTorquesElMaster_mNm; 233 | std::vector m_voMotorTorquesElSlave_mNm; 234 | 235 | std::vector m_voNoiseDiodeSoftwareStates; 236 | std::vector m_voNoiseDiodeSources; 237 | std::vector m_voNoiseDiodeCurrents; 238 | 239 | std::vector m_voSelectedSources; 240 | 241 | std::vector m_voFrequencySelectLCP; 242 | std::vector m_voFrequencySelectRCP; 243 | std::vector m_voFrequenciesLO0Chan0_Hz; 244 | std::vector m_voFrequenciesLO0Chan1_Hz; 245 | std::vector m_voFrequenciesLO1_Hz; 246 | std::vector m_voReceiverBandwidthsChan0_Hz; 247 | std::vector m_voReceiverBandwidthsChan1_Hz; 248 | 249 | cAntennaConfiguration m_oAntennaConfiguration; 250 | std::vector m_vdDelayModelParams; 251 | std::vector m_vdPointingModelParams; //Only store most recent version 252 | 253 | //Values received from ROACH TCPBorphServer 254 | std::vector m_voROACHAccumulationLengths_nFrames; 255 | std::vector m_voROACHNBChannelSelects; 256 | double m_dROACHFrequencyFs_Hz; //Only store most recent version (shouldn't ever change from 800 MHz) 257 | uint32_t m_u32ROACHSizeOfCoarseFFT_nSamp; //Only store most recent version (shouldn't ever change for a given gateware) 258 | uint32_t m_u32ROACHSizeOfFineFFT_nSamp; //Only store most recent version (shouldn't ever change for a given gateware) 259 | std::vector m_voROACHCoarseFFTShiftMasks; 260 | std::vector m_voROACHADCAttenuationsChan0_dB; 261 | std::vector m_voROACHADCAttenuationsChan1_dB; 262 | 263 | //Other 264 | cSpectrometerHeader m_oLastHeader; 265 | 266 | boost::shared_mutex m_oAppendDataMutex; //share-locked for augmenting all station controller and TCPBorph data. Unique locked when writing this data to file 267 | 268 | float calculateFrameAverage(const std::vector &vi32ChannelData); 269 | 270 | void addAttributesToFile(const std::string &strVersion, const std::string &strExperimentID, int64_t i64AugmentTimestamp_us, uint32_t u32AugmentErrors, hid_t fileHandle); 271 | void addAttributeToDataSet(const std::string &strDescription, const std::string &strName, const std::string &strType, const std::string &strUnits, hid_t dataset); 272 | void addAttributesToObservation( 273 | const std::string &strScriptName, 274 | const std::string &strScriptArguments, 275 | const std::string &strObserver, 276 | const std::string &strExperimentID, 277 | const std::string &strDescription, 278 | const std::string &strAntennas, 279 | const std::string &strStartTime, 280 | const std::string &strEndTime, 281 | const std::string &strNoiseDiodeParams, 282 | const std::string &strRFParams, 283 | const std::string &strStatus, 284 | hid_t observationGroup 285 | ); 286 | void addAttributesToDBE(const std::string &strVisOrdering, const std::string &strStokesOrdering, hid_t DBEGroup); 287 | 288 | //Write logged data to file (after sample recording is completed) 289 | void writeSampleDataTimestamps(); 290 | void writeChannelAverages(); 291 | void writeROACHNoiseDiodeStates(); 292 | 293 | void writeMarkupLabels(); 294 | 295 | void writeRequestedAntennaAzEls(); 296 | void writeActualAntennaAzEls(); 297 | void writeActualSourceOffsetAzEls(); 298 | void writeActualAntennaRADecs(); 299 | 300 | void writeAntennaStatuses(); 301 | void writeMotorTorques(); 302 | void writeAntennaConfiguration(); 303 | 304 | void writeNoiseDiodeSoftwareStates(); 305 | void writeNoiseDiodeSources(); 306 | void writeNoideDiodeCurrents(); 307 | 308 | void writeSelectedSources(); 309 | 310 | void writeRFFrequencies(); 311 | void writeLOFrequencies(); 312 | void writeIFBandwidths(); 313 | 314 | void writeROACHNumberChannels(); 315 | void writeROACHAccumulationLengths(); 316 | void writeROACHNBNarrowbandSelections(); 317 | void writeROACHSamplingFreqBandwidth(); 318 | void writeROACHSizeOfFFTs(); 319 | void writeROACHCoarseFFTShiftMask(); 320 | void writeROACHAdcAttentuations(); 321 | 322 | }; 323 | 324 | #endif // SPECTROMETER_HDF5_OUTPUT_FILE_H 325 | -------------------------------------------------------------------------------- /SpectrometerHDF5OutputFile.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | #include 4 | #include 5 | #include 6 | 7 | //Library includes 8 | extern "C" { 9 | #include //Note must be included before other HDF5 libraries 10 | #include 11 | } 12 | 13 | #include 14 | #include 15 | namespace pt = boost::property_tree; 16 | 17 | //Local includes 18 | #include "SpectrometerHDF5OutputFile.h" 19 | #include "../../AVNUtilLibs/Timestamp/Timestamp.h" 20 | #include "../../AVNUtilLibs/CoordinatePosition/CoordinatePosition.h" 21 | 22 | using namespace std; 23 | 24 | cSpectrometerHDF5OutputFile::cSpectrometerHDF5OutputFile(const std::string &strFilename, AVN::Spectrometer::digitiserType eDigitiserType, uint32_t u32NFrequencyBins) : 25 | m_strFilename(strFilename), 26 | m_eDigitiserType(eDigitiserType), 27 | m_u32NFrequencyBins(u32NFrequencyBins), 28 | m_vvfChannelAverages(4) 29 | { 30 | //Create file (overwrite any existing one with the same name) 31 | m_iH5FileHandle = H5Fcreate(m_strFilename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); 32 | 33 | if(m_iH5FileHandle == H5I_INVALID_HID) 34 | { 35 | cout << "Error opening HDF5 file." << endl; 36 | } 37 | 38 | //Setup data groups (hierachy like a directory structure within the HDF5 container): 39 | //Level 1: 40 | m_iH5DataGroupHandle = H5Gcreate2(m_iH5FileHandle, "/Data", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 41 | m_iH5MetaDataGroupHandle = H5Gcreate2(m_iH5FileHandle, "/MetaData", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 42 | m_iH5MarkupGroupHandle = H5Gcreate2(m_iH5FileHandle, "/Markup", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 43 | //Level 2: 44 | m_iH5SensorsGroupHandle = H5Gcreate2(m_iH5MetaDataGroupHandle, "/MetaData/Sensors", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 45 | m_iH5ConfigurationGroupHandle = H5Gcreate2(m_iH5MetaDataGroupHandle, "/MetaData/Configuration", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 46 | //Level 3: 47 | m_iH5SensorsAntennasGroupHandle = H5Gcreate2(m_iH5SensorsGroupHandle, "/MetaData/Sensors/Antennas", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 48 | m_iH5SensorsRFEGroupHandle = H5Gcreate2(m_iH5SensorsGroupHandle, "/MetaData/Sensors/RFE", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 49 | m_iH5SensorsDBEGroupHandle = H5Gcreate2(m_iH5SensorsGroupHandle, "/MetaData/Sensors/DBE", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 50 | m_iH5ConfigurationAntennasGroupHandle = H5Gcreate2(m_iH5ConfigurationGroupHandle, "/MetaData/Configuration/Antennas", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 51 | m_iH5ConfigurationObservationGroupHandle = H5Gcreate2(m_iH5MetaDataGroupHandle, "/MetaData/Configuration/Observation", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 52 | m_iH5ConfigurationDBEGroupHandle = H5Gcreate2(m_iH5MetaDataGroupHandle, "/MetaData/Configuration/DBE", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 53 | //Level 4: 54 | m_iH5SensorsAntennasAntenna1GroupHandle = H5Gcreate2(m_iH5SensorsAntennasGroupHandle, "/MetaData/Sensors/Antennas/ant1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 55 | m_iH5ConfigurationAntennasAntenna1GroupHandle = H5Gcreate2(m_iH5ConfigurationAntennasGroupHandle, "/MetaData/Configuration/Antennas/ant1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 56 | 57 | //Note data dimensions are [ time x frequency bin x data channel ] 58 | m_aChannelDatasetDims[0] = 1; 59 | m_aChannelDatasetDims[1] = m_u32NFrequencyBins; 60 | m_aChannelDatasetDims[2] = 2; 61 | 62 | m_aChannelDatasetExtensionDims[0] = 1; 63 | m_aChannelDatasetExtensionDims[1] = m_aChannelDatasetDims[1]; 64 | m_aChannelDatasetExtensionDims[2] = m_aChannelDatasetDims[2]; 65 | 66 | m_aMemspaceSize[0] = 1; 67 | m_aMemspaceSize[1] = m_aChannelDatasetExtensionDims[1]; 68 | m_aMemspaceSize[2] = 1; 69 | 70 | m_aChannelDataOffset[0] = 0; 71 | m_aChannelDataOffset[1] = 0; 72 | m_aChannelDataOffset[2] = 0; 73 | 74 | hsize_t maxDims[3] = {H5S_UNLIMITED, H5S_UNLIMITED, H5S_UNLIMITED}; 75 | 76 | // Create a dataset creation property list and set it to use chunking 77 | hid_t datasetPropertiesVis = H5Pcreate(H5P_DATASET_CREATE); 78 | hid_t datasetPropertiesStokes = H5Pcreate(H5P_DATASET_CREATE); 79 | H5Pset_chunk(datasetPropertiesVis, 3, m_aChannelDatasetDims); 80 | H5Pset_chunk(datasetPropertiesStokes, 3, m_aChannelDatasetDims); 81 | 82 | /* Create the dataspace and the chunked dataset */ 83 | hid_t dataSpaceVis = H5Screate_simple(3, m_aChannelDatasetDims, maxDims); 84 | hid_t dataSpaceStokes = H5Screate_simple(3, m_aChannelDatasetDims, maxDims); 85 | 86 | 87 | m_iH5DatasetVis = H5Dcreate1(m_iH5DataGroupHandle, "VisData", H5T_NATIVE_INT, dataSpaceVis, datasetPropertiesVis); 88 | m_iH5DatasetStokes = H5Dcreate1(m_iH5DataGroupHandle, "StokesData", H5T_NATIVE_INT, dataSpaceStokes, datasetPropertiesStokes); 89 | 90 | 91 | if(m_iH5DatasetVis == H5I_INVALID_HID || m_iH5DatasetStokes == H5I_INVALID_HID) 92 | { 93 | cout << "Error: Creating HDF5 datasets failed." << endl; 94 | } 95 | else 96 | { 97 | cout << "Successfully created HDF5 datasets." << endl; 98 | } 99 | 100 | H5Sclose(dataSpaceVis); 101 | H5Sclose(dataSpaceStokes); 102 | H5Pclose(datasetPropertiesVis); 103 | H5Pclose(datasetPropertiesStokes); 104 | 105 | //Read antenna config information from ini file 106 | pt::ptree ObsInfo; 107 | pt::ini_parser::read_ini("ObservatoryInfo.ini", ObsInfo); 108 | setAntennaName(ObsInfo.get("Antenna.name")); 109 | setAntennaLatitude(ObsInfo.get("Antenna.latitude")); 110 | setAntennaLongitude(ObsInfo.get("Antenna.longitude")); 111 | setAntennaAltitude(ObsInfo.get("Antenna.altitude")); 112 | setAntennaDiameter(ObsInfo.get("Antenna.diameter")); 113 | setAntennaBeamwidth(ObsInfo.get("Antenna.beamwidth")); 114 | 115 | //Assume zero delay and pointing models. Maybe incorporate in config file in future? 116 | vector vdZeroModelParams; 117 | for(int ui = 0; ui < 22; ui++) 118 | { 119 | vdZeroModelParams.push_back(0.0); 120 | if (ui == 2) // i.e. we've reached the third one. 121 | setAntennaDelayModel(vdZeroModelParams); 122 | } 123 | setAppliedPointingModel("vlbi", vdZeroModelParams); 124 | 125 | } 126 | 127 | cSpectrometerHDF5OutputFile::~cSpectrometerHDF5OutputFile() 128 | { 129 | cout << "cSpectrometerHDF5OutputFile::~cSpectrometerHDF5OutputFile(): Got close request, writing accumulated data to end of HDF5 file... " << endl; 130 | 131 | // TODO: This data needs to be retrieved from the KatCP server. Somewhere. 132 | string strExperimentID("test_experiment"); 133 | addAttributesToFile("2.5", strExperimentID, AVN::getTimeNow_us(), 0, m_iH5FileHandle); // Zero errors, because our software is perfect! 134 | addAttributesToObservation("script name", "script arguments", "Observer name", strExperimentID, "description", "ant1", "start time", "end time", "noise diode params", "rf params", "status", m_iH5ConfigurationObservationGroupHandle); 135 | addAttributesToDBE("ll,rr", "q,u", m_iH5ConfigurationDBEGroupHandle); 136 | 137 | writeMarkupLabels(); 138 | 139 | writeSampleDataTimestamps(); 140 | writeChannelAverages(); 141 | writeROACHNoiseDiodeStates(); 142 | 143 | writeRequestedAntennaAzEls(); 144 | writeActualAntennaAzEls(); 145 | writeActualSourceOffsetAzEls(); 146 | writeActualAntennaRADecs(); 147 | 148 | writeAntennaStatuses(); 149 | writeMotorTorques(); 150 | writeAntennaConfiguration(); 151 | 152 | writeNoiseDiodeSoftwareStates(); 153 | writeNoiseDiodeSources(); 154 | writeNoideDiodeCurrents(); 155 | 156 | writeSelectedSources(); 157 | 158 | writeRFFrequencies(); 159 | writeLOFrequencies(); 160 | writeIFBandwidths(); 161 | 162 | writeROACHAccumulationLengths(); 163 | writeROACHNBNarrowbandSelections(); 164 | writeROACHSamplingFreqBandwidth(); 165 | writeROACHNumberChannels(); 166 | writeROACHSizeOfFFTs(); 167 | writeROACHCoarseFFTShiftMask(); 168 | writeROACHAdcAttentuations(); 169 | 170 | cout << "cSpectrometerHDF5OutputFile::~cSpectrometerHDF5OutputFile(): Done writing accumulated data." << endl; 171 | 172 | //Close and free all HDF5 structures 173 | H5Dclose(m_iH5DatasetVis); 174 | H5Dclose(m_iH5DatasetStokes); 175 | 176 | //HDF5 groups close deepest first: 177 | //Level 4 178 | H5Gclose(m_iH5SensorsAntennasAntenna1GroupHandle); 179 | H5Gclose(m_iH5ConfigurationAntennasAntenna1GroupHandle); 180 | H5Gclose(m_iH5ConfigurationDBEGroupHandle); 181 | //Level 3 182 | H5Gclose(m_iH5SensorsAntennasGroupHandle); 183 | H5Gclose(m_iH5SensorsRFEGroupHandle); 184 | H5Gclose(m_iH5SensorsDBEGroupHandle); 185 | H5Gclose(m_iH5ConfigurationAntennasGroupHandle); 186 | H5Gclose(m_iH5ConfigurationObservationGroupHandle); 187 | //Level 2 188 | H5Gclose(m_iH5SensorsGroupHandle); 189 | H5Gclose(m_iH5ConfigurationGroupHandle); 190 | //Level 1 191 | H5Gclose(m_iH5MarkupGroupHandle); 192 | H5Gclose(m_iH5MetaDataGroupHandle); 193 | H5Gclose(m_iH5DataGroupHandle); 194 | 195 | //Level 0 (file) 196 | H5Fclose(m_iH5FileHandle); 197 | } 198 | 199 | string cSpectrometerHDF5OutputFile::getFilename() const 200 | { 201 | return m_strFilename; 202 | } 203 | 204 | void cSpectrometerHDF5OutputFile::addFrame(const std::vector &vi32Chan0, const std::vector &vi32Chan1, const std::vector &vi32Chan2, std::vector &vi32Chan3, 205 | const cSpectrometerHeader &oHeader) 206 | { 207 | m_aChannelDatasetDims[0] += m_aChannelDatasetExtensionDims[0]; //Extend in the time dimension 208 | 209 | //Visibilty dataset (LL + RR) 210 | ////////////////////////////////////////////////////////////////////////////////////////////////////// 211 | H5Dset_extent(m_iH5DatasetVis, m_aChannelDatasetDims); 212 | hid_t filespaceVis = H5Dget_space(m_iH5DatasetVis); 213 | 214 | m_aChannelDataOffset[2] = 0; 215 | H5Sselect_hyperslab (filespaceVis, H5S_SELECT_SET, m_aChannelDataOffset, NULL, m_aMemspaceSize, NULL); 216 | hid_t memspace0 = H5Screate_simple (3, m_aMemspaceSize, NULL); 217 | 218 | herr_t err0 = H5Dwrite(m_iH5DatasetVis, H5T_NATIVE_INT, memspace0, filespaceVis, H5P_DEFAULT, &vi32Chan0.front()); 219 | if(err0 < 0) 220 | { 221 | cout << "HDF5 chunk extend error on 1st channel: " << err0 << endl; 222 | } 223 | 224 | m_aChannelDataOffset[2] = 1; 225 | H5Sselect_hyperslab (filespaceVis, H5S_SELECT_SET, m_aChannelDataOffset, NULL, m_aMemspaceSize, NULL); 226 | hid_t memspace1 = H5Screate_simple (3, m_aMemspaceSize, NULL); 227 | 228 | herr_t err1 = H5Dwrite(m_iH5DatasetVis, H5T_NATIVE_INT, memspace1, filespaceVis, H5P_DEFAULT, &vi32Chan1.front()); 229 | if(err1 < 0) 230 | { 231 | cout << "HDF5 chunk extend error on 2nd channel: " << err1 << endl; 232 | } 233 | 234 | //Stokes dataset (Q + U) 235 | ////////////////////////////////////////////////////////////////////////////////////////////////////// 236 | H5Dset_extent(m_iH5DatasetStokes, m_aChannelDatasetDims); 237 | hid_t filespaceStokes = H5Dget_space(m_iH5DatasetStokes); 238 | 239 | m_aChannelDataOffset[2] = 0; 240 | H5Sselect_hyperslab (filespaceStokes, H5S_SELECT_SET, m_aChannelDataOffset, NULL, m_aMemspaceSize, NULL); 241 | hid_t memspace2 = H5Screate_simple (3, m_aMemspaceSize, NULL); 242 | 243 | herr_t err2 = H5Dwrite(m_iH5DatasetStokes, H5T_NATIVE_INT, memspace2, filespaceStokes, H5P_DEFAULT, &vi32Chan2.front()); 244 | if(err2 < 0) 245 | { 246 | cout << "HDF5 chunk extend error on 3rd channel: " << err2 << endl; 247 | } 248 | 249 | m_aChannelDataOffset[2] = 1; 250 | H5Sselect_hyperslab (filespaceStokes, H5S_SELECT_SET, m_aChannelDataOffset, NULL, m_aMemspaceSize, NULL); 251 | hid_t memspace3 = H5Screate_simple (3, m_aMemspaceSize, NULL); 252 | 253 | herr_t err3 = H5Dwrite(m_iH5DatasetStokes, H5T_NATIVE_INT, memspace3, filespaceStokes, H5P_DEFAULT, &vi32Chan3.front()); 254 | if(err3 < 0) 255 | { 256 | cout << "HDF5 chunk extend error on 4th channel: " << err3 << endl; 257 | } 258 | 259 | H5Sclose (memspace0); 260 | H5Sclose (memspace1); 261 | H5Sclose (memspace2); 262 | H5Sclose (memspace3); 263 | 264 | H5Sclose (filespaceVis); 265 | H5Sclose (filespaceStokes); 266 | 267 | //Store values to be written after channel data in memory: 268 | //(Not written directly to disk because they will be interleaved on the disk and cause long read times.) 269 | 270 | //Data entry timestamps 271 | double dTimestamp_s = (double)oHeader.getTimestamp_us() / 1e6; 272 | m_vdSampleDataTimestamps_s.push_back(dTimestamp_s); //As per KAT7 data: Seconds since Unix Epoch stored as double. 273 | 274 | //Data averages 275 | m_vvfChannelAverages[0].push_back( calculateFrameAverage(vi32Chan0) ); 276 | m_vvfChannelAverages[1].push_back( calculateFrameAverage(vi32Chan1) ); 277 | m_vvfChannelAverages[2].push_back( calculateFrameAverage(vi32Chan2) ); 278 | m_vvfChannelAverages[3].push_back( calculateFrameAverage(vi32Chan3) ); 279 | 280 | //Noise diode state changes 281 | if(oHeader.getNoiseDiodeOn() != m_oLastHeader.getNoiseDiodeOn() || !m_voROACHNoiseDiodeStateChanges.size()) 282 | { 283 | cTimestampedChar oState; 284 | 285 | oState.m_dTimestamp_s = dTimestamp_s; 286 | 287 | if(oHeader.getNoiseDiodeOn()) 288 | { 289 | oState.m_chaValue[0] = '1'; 290 | } 291 | else 292 | { 293 | oState.m_chaValue[0] = '0'; 294 | } 295 | 296 | sprintf(oState.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. 297 | //At present AVN doesn't make hardware provision for any sort of feedback with the noise diode 298 | 299 | m_voROACHNoiseDiodeStateChanges.push_back(oState); 300 | } 301 | 302 | m_aChannelDataOffset[0] += m_aChannelDatasetExtensionDims[0]; 303 | 304 | m_oLastHeader = oHeader; 305 | 306 | } 307 | 308 | void cSpectrometerHDF5OutputFile::writeSampleDataTimestamps() 309 | { 310 | hsize_t dimension = m_vdSampleDataTimestamps_s.size(); 311 | herr_t err = H5LTmake_dataset(m_iH5DataGroupHandle, "Timestamps", 1, &dimension, H5T_NATIVE_DOUBLE, &m_vdSampleDataTimestamps_s.front()); 312 | 313 | if(err < 0) 314 | { 315 | cout << "cSpectrometerHDF5OutputFile::writeTimestamps(): HDF5 make dataset error" << endl; 316 | } 317 | else 318 | { 319 | cout << "cSpectrometerHDF5OutputFile::writeTimestamps(): Wrote " << m_vdSampleDataTimestamps_s.size() << " timestamps to dataset." << endl; 320 | } 321 | } 322 | 323 | void cSpectrometerHDF5OutputFile::writeChannelAverages() 324 | { 325 | hsize_t dimension; 326 | 327 | for(uint64_t ui = 0; ui < m_vvfChannelAverages.size(); ui++) 328 | { 329 | dimension = m_vvfChannelAverages[ui].size(); 330 | 331 | stringstream oSS; 332 | oSS << AVN::Spectrometer::getDigitiserChannelName(m_oLastHeader.getDigitiserType(), ui); 333 | oSS << string(" time average"); 334 | 335 | herr_t err = H5LTmake_dataset(m_iH5DataGroupHandle, oSS.str().c_str(), 1, &dimension, H5T_NATIVE_FLOAT, &m_vvfChannelAverages[ui].front()); 336 | 337 | if(err < 0) 338 | { 339 | cout << "cSpectrometerHDF5OutputFile::writeChannelAverages(): HDF5 make dataset error for channel " << ui << endl; 340 | } 341 | else 342 | { 343 | cout << "cSpectrometerHDF5OutputFile::writeChannelAverages(): Wrote " << m_vvfChannelAverages[ui].size() << " time averages to dataset for channel " << ui << "." << endl; 344 | } 345 | } 346 | } 347 | 348 | void cSpectrometerHDF5OutputFile::writeROACHNoiseDiodeStates() 349 | { 350 | //This vector should always have at least one vector in it, and the noise diode 351 | //should by default be off (handled elsewhere). 352 | string strDatasetName("noise-diode.roach.on"); 353 | 354 | //Create the data space 355 | hsize_t dimension[] = { m_voROACHNoiseDiodeStateChanges.size() }; 356 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 357 | 358 | //Create a compound data type consisting of different native types per entry: 359 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedChar)); 360 | 361 | //Add to compound data type: a timestamp (double) 362 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedChar, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 363 | 364 | //Add to compound data type: the noise diode state (string of 1 character "0" or "1") 365 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 366 | H5Tset_size(stringTypeValue, sizeof(cTimestampedChar::m_chaValue)); 367 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedChar, m_chaValue), stringTypeValue); 368 | 369 | //Add to compound data type: the status of the noise diode equiptment (string typically containing "nominal") 370 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 371 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedChar::m_chaStatus)); 372 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedChar, m_chaStatus), stringTypeStatus); 373 | 374 | //Create the data set of of the new compound datatype 375 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 376 | 377 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voROACHNoiseDiodeStateChanges.front()); 378 | 379 | if(err < 0) 380 | { 381 | cout << "cSpectrometerHDF5OutputFile::writeNoiseDiodeStates(): HDF5 make dataset error" << endl; 382 | } 383 | else 384 | { 385 | cout << "cSpectrometerHDF5OutputFile::writeNoiseDiodeStates(): Wrote " << m_voROACHNoiseDiodeStateChanges.size() << " noise diode states to dataset." << endl; 386 | } 387 | 388 | addAttributeToDataSet(string("AVN frontend noise diode"), strDatasetName, string("boolean"), string(""), dataset); 389 | 390 | H5Tclose(stringTypeValue); 391 | H5Tclose(stringTypeStatus); 392 | H5Tclose(compoundDataType); 393 | H5Sclose(dataspace); 394 | H5Dclose(dataset); 395 | } 396 | 397 | void cSpectrometerHDF5OutputFile::writeMarkupLabels() 398 | { 399 | //If the vector is empty, no point in adding it to the HDF5 file. 400 | if (m_voMarkupLabels.size()) 401 | { 402 | string strDatasetName("labels"); 403 | 404 | //Create the data space TODO 405 | hsize_t dimension[] = { m_voMarkupLabels.size() }; 406 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 407 | 408 | //Create a compound data type consisting of different native types per entry: 409 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cMarkupLabels)); 410 | 411 | //Add to compound data type: a timestamp (double) 412 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cMarkupLabels, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 413 | 414 | //Add to compound data type: the label (string) 415 | hid_t stringTypeLabel = H5Tcopy (H5T_C_S1); 416 | H5Tset_size(stringTypeLabel, sizeof(cMarkupLabels::m_chaLabel)); 417 | H5Tinsert(compoundDataType, "label", HOFFSET(cMarkupLabels, m_chaLabel), stringTypeLabel); 418 | 419 | //Create the data set of of the new compound datatype 420 | hid_t dataset = H5Dcreate1(m_iH5MarkupGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 421 | 422 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voMarkupLabels.front()); 423 | 424 | if(err < 0) 425 | { 426 | cout << "cSpectrometerHDF5OutputFile::writeMarkupLabels(): HDF5 make dataset error" << endl; 427 | } 428 | else 429 | { 430 | cout << "cSpectrometerHDF5OutputFile::writeMarkupLabels(): Wrote " << m_voMarkupLabels.size() << " markup labels to dataset." << endl; 431 | } 432 | 433 | H5Tclose(stringTypeLabel); 434 | H5Tclose(compoundDataType); 435 | H5Sclose(dataspace); 436 | H5Dclose(dataset); 437 | } 438 | } 439 | 440 | void cSpectrometerHDF5OutputFile::writeRequestedAntennaAzEls() 441 | { 442 | //Requested values to motor drive after pointing model 443 | //As per KAT7 Azimuth and elevation are in seperate datasets 444 | 445 | //Azimuth: 446 | //////////////////////////////////////////////////////////////////////////////////////////// 447 | if (m_voRequestedAntennaAzs_deg.size()) 448 | { 449 | string strDatasetName("pos.request-scan-azim"); 450 | 451 | //Create the data space 452 | hsize_t dimension[] = { m_voRequestedAntennaAzs_deg.size() }; 453 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 454 | 455 | //Create a compound data type consisting of different native types per entry: 456 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 457 | 458 | //Add to compound data type: a timestamp (double) 459 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 460 | 461 | //Add to compound data type: the azimuth value (double) 462 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 463 | 464 | //Add to compound data type: the status of the elevation sensor (string typically containing "nominal") 465 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 466 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 467 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 468 | 469 | //Create the data set of of the new compound datatype 470 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 471 | 472 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voRequestedAntennaAzs_deg.front()); 473 | 474 | if(err < 0) 475 | { 476 | cout << "cSpectrometerHDF5OutputFile::writeRequestedAntennaAzEls(): HDF5 make dataset error" << endl; 477 | } 478 | else 479 | { 480 | cout << "cSpectrometerHDF5OutputFile::writeRequestedAntennaAzEls(): Wrote " << m_voRequestedAntennaAzs_deg.size() << " requested antenna azimuths to dataset." << endl; 481 | } 482 | 483 | addAttributeToDataSet(string("Requested azimuth after scan offset"), strDatasetName, string("double"), string("deg"), dataset); 484 | 485 | H5Tclose(stringTypeStatus); 486 | H5Tclose(compoundDataType); 487 | H5Sclose(dataspace); 488 | H5Dclose(dataset); 489 | } 490 | 491 | //Elevation: 492 | //////////////////////////////////////////////////////////////////////////////////////////// 493 | if (m_voRequestedAntennaEls_deg.size()) 494 | { 495 | string strDatasetName("pos.request-scan-elev"); 496 | 497 | //Create the data space 498 | hsize_t dimension[] = { m_voRequestedAntennaEls_deg.size() }; 499 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 500 | 501 | //Create a compound data type consisting of different native types per entry: 502 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 503 | 504 | //Add to compound data type: a timestamp (double) 505 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 506 | 507 | //Add to compound data type: the elevation value (double) 508 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 509 | 510 | //Add to compound data type: the status of the elevation sensor (string typically containing "nominal") 511 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 512 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 513 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 514 | 515 | //Create the data set of of the new compound datatype 516 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 517 | 518 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voRequestedAntennaEls_deg.front()); 519 | 520 | if(err < 0) 521 | { 522 | cout << "cSpectrometerHDF5OutputFile::writeRequestedAntennaAzEls(): HDF5 make dataset error" << endl; 523 | } 524 | else 525 | { 526 | cout << "cSpectrometerHDF5OutputFile::writeRequestedAntennaAzEls(): Wrote " << m_voRequestedAntennaEls_deg.size() << " requested antenna elevations to dataset." << endl; 527 | } 528 | 529 | addAttributeToDataSet(string("Requested elevation after scan offset"), strDatasetName, string("double"), string("deg"), dataset); 530 | 531 | H5Tclose(stringTypeStatus); 532 | H5Tclose(compoundDataType); 533 | H5Sclose(dataspace); 534 | H5Dclose(dataset); 535 | } 536 | } 537 | 538 | void cSpectrometerHDF5OutputFile::writeActualAntennaAzEls() 539 | { 540 | //Values return from drive about current Az/El 541 | //Apply inverse pointing model to get to ideal Az/El 542 | 543 | //Requested values to motor drive after pointing model 544 | //As per KAT7 Azimuth and elevation are in seperate datasets 545 | 546 | //Azimuth: 547 | //////////////////////////////////////////////////////////////////////////////////////////// 548 | if (m_voActualAntennaAzs_deg.size()) 549 | { 550 | string strDatasetName("pos.actual-scan-azim"); 551 | 552 | //Create the data space 553 | hsize_t dimension[] = { m_voActualAntennaAzs_deg.size() }; 554 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 555 | 556 | //Create a compound data type consisting of different native types per entry: 557 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 558 | 559 | //Add to compound data type: a timestamp (double) 560 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 561 | 562 | //Add to compound data type: the azimuth value (double) 563 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 564 | 565 | //Add to compound data type: the status of the elevation sensor (string typically containing "nominal") 566 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 567 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 568 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 569 | 570 | //Create the data set of of the new compound datatype 571 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 572 | 573 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voActualAntennaAzs_deg.front()); 574 | 575 | if(err < 0) 576 | { 577 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaAzEls(): HDF5 make dataset error" << endl; 578 | } 579 | else 580 | { 581 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaAzEls(): Wrote " << m_voActualAntennaAzs_deg.size() << " actual antenna azimuths to dataset." << endl; 582 | } 583 | 584 | addAttributeToDataSet(string("Actual azimuth after scan offset"), strDatasetName, string("double"), string("deg"), dataset); 585 | 586 | H5Tclose(stringTypeStatus); 587 | H5Tclose(compoundDataType); 588 | H5Sclose(dataspace); 589 | H5Dclose(dataset); 590 | } 591 | 592 | //Elevation: 593 | //////////////////////////////////////////////////////////////////////////////////////////// 594 | if (m_voActualAntennaEls_deg.size()) 595 | { 596 | string strDatasetName("pos.actual-scan-elev"); 597 | 598 | //Create the data space 599 | hsize_t dimension[] = { m_voActualAntennaEls_deg.size() }; 600 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 601 | 602 | //Create a compound data type consisting of different native types per entry: 603 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 604 | 605 | //Add to compound data type: a timestamp (double) 606 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 607 | 608 | //Add to compound data type: the elevation value (double) 609 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 610 | 611 | //Add to compound data type: the status of the elevation sensor (string typically containing "nominal") 612 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 613 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 614 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 615 | 616 | //Create the data set of of the new compound datatype 617 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 618 | 619 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voActualAntennaEls_deg.front()); 620 | 621 | if(err < 0) 622 | { 623 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaAzEls(): HDF5 make dataset error" << endl; 624 | } 625 | else 626 | { 627 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaAzEls(): Wrote " << m_voActualAntennaEls_deg.size() << " actual antenna elevations to dataset." << endl; 628 | } 629 | 630 | addAttributeToDataSet(string("Actual elevation after scan offset"), strDatasetName, string("double"), string("deg"), dataset); 631 | 632 | H5Tclose(stringTypeStatus); 633 | H5Tclose(compoundDataType); 634 | H5Sclose(dataspace); 635 | H5Dclose(dataset); 636 | } 637 | } 638 | 639 | void cSpectrometerHDF5OutputFile::writeActualSourceOffsetAzEls() 640 | { 641 | if (m_voActualSourceOffsetAzs_deg.size()) 642 | { 643 | string strDatasetName("pos.source-offset-azim"); 644 | 645 | //Create the data space 646 | hsize_t dimension[] = { m_voActualSourceOffsetAzs_deg.size() }; 647 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 648 | 649 | //Create a compound data type consisting of different native types per entry: 650 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 651 | 652 | //Add to compound data type: a timestamp (double) 653 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 654 | 655 | //Add to compound data type: the azimuth value (double) 656 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 657 | 658 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 659 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 660 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 661 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 662 | 663 | //Create the data set of of the new compound datatype 664 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 665 | 666 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voActualSourceOffsetAzs_deg.front()); 667 | 668 | if(err < 0) 669 | { 670 | cout << "cSpectrometerHDF5OutputFile::writeActualSourceOffsetAzEls(): HDF5 make dataset error" << endl; 671 | } 672 | else 673 | { 674 | cout << "cSpectrometerHDF5OutputFile::writeActualSourceOffsetAzEls(): Wrote " << m_voActualSourceOffsetAzs_deg.size() << " actual source azimuth offsets to dataset." << endl; 675 | } 676 | 677 | addAttributeToDataSet(string("Azimuth offset from the source after pointing model"), strDatasetName, string("double"), string("deg"), dataset); 678 | 679 | H5Tclose(stringTypeStatus); 680 | H5Tclose(compoundDataType); 681 | H5Sclose(dataspace); 682 | H5Dclose(dataset); 683 | } 684 | 685 | if (m_voActualSourceOffsetEls_deg.size()) 686 | { 687 | string strDatasetName("pos.source-offset-elev"); 688 | 689 | //Create the data space 690 | hsize_t dimension[] = { m_voActualSourceOffsetEls_deg.size() }; 691 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 692 | 693 | //Create a compound data type consisting of different native types per entry: 694 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 695 | 696 | //Add to compound data type: a timestamp (double) 697 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 698 | 699 | //Add to compound data type: the elevation value (double) 700 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 701 | 702 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 703 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 704 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 705 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 706 | 707 | //Create the data set of of the new compound datatype 708 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 709 | 710 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voActualSourceOffsetEls_deg.front()); 711 | 712 | if(err < 0) 713 | { 714 | cout << "cSpectrometerHDF5OutputFile::writeActualSourceOffsetAzEls(): HDF5 make dataset error" << endl; 715 | } 716 | else 717 | { 718 | cout << "cSpectrometerHDF5OutputFile::writeActualSourceOffsetAzEls(): Wrote " << m_voActualSourceOffsetEls_deg.size() << " actual source elevation offsets to dataset." << endl; 719 | } 720 | 721 | addAttributeToDataSet(string("Elevation offset from the source after pointing model"), strDatasetName, string("double"), string("deg"), dataset); 722 | 723 | H5Tclose(stringTypeStatus); 724 | H5Tclose(compoundDataType); 725 | H5Sclose(dataspace); 726 | H5Dclose(dataset); 727 | } 728 | } 729 | 730 | void cSpectrometerHDF5OutputFile::writeActualAntennaRADecs() 731 | { 732 | if (m_voActualAntennaRAs_deg.size()) 733 | { 734 | string strDatasetName("pos.actual-ra"); 735 | 736 | //Create the data space 737 | hsize_t dimension[] = { m_voActualAntennaRAs_deg.size() }; 738 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 739 | 740 | //Create a compound data type consisting of different native types per entry: 741 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 742 | 743 | //Add to compound data type: a timestamp (double) 744 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 745 | 746 | //Add to compound data type: the RA value (double) 747 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 748 | 749 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 750 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 751 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 752 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 753 | 754 | //Create the data set of of the new compound datatype 755 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 756 | 757 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voActualAntennaRAs_deg.front()); 758 | 759 | if(err < 0) 760 | { 761 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaRADecs(): HDF5 make dataset error" << endl; 762 | } 763 | else 764 | { 765 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaRADecs(): Wrote " << m_voActualAntennaRAs_deg.size() << " actual RAs to dataset." << endl; 766 | } 767 | 768 | addAttributeToDataSet(string("Actual right ascention derived from actual azimuth/elevation after pointing model"), strDatasetName, string("double"), string("deg"), dataset); 769 | 770 | H5Tclose(stringTypeStatus); 771 | H5Tclose(compoundDataType); 772 | H5Sclose(dataspace); 773 | H5Dclose(dataset); 774 | } 775 | 776 | if (m_voActualAntennaRAs_deg.size()) 777 | { 778 | string strDatasetName("pos.actual-dec"); 779 | 780 | //Create the data space 781 | hsize_t dimension[] = { m_voActualAntennaRAs_deg.size() }; 782 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 783 | 784 | //Create a compound data type consisting of different native types per entry: 785 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 786 | 787 | //Add to compound data type: a timestamp (double) 788 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 789 | 790 | //Add to compound data type: the Dec value (double) 791 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 792 | 793 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 794 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 795 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 796 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 797 | 798 | //Create the data set of of the new compound datatype 799 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 800 | 801 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voActualAntennaRAs_deg.front()); 802 | 803 | if(err < 0) 804 | { 805 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaRADecs(): HDF5 make dataset error" << endl; 806 | } 807 | else 808 | { 809 | cout << "cSpectrometerHDF5OutputFile::writeActualAntennaRADecs(): Wrote " << m_voActualAntennaRAs_deg.size() << " actual Decs to dataset." << endl; 810 | } 811 | 812 | addAttributeToDataSet(string("Actual declination derived from actual azimuth/elevation after pointing model"), strDatasetName, string("double"), string("deg"), dataset); 813 | 814 | H5Tclose(stringTypeStatus); 815 | H5Tclose(compoundDataType); 816 | H5Sclose(dataspace); 817 | H5Dclose(dataset); 818 | } 819 | } 820 | 821 | void cSpectrometerHDF5OutputFile::writeAntennaStatuses() 822 | { 823 | if (m_voAntennaStatuses.size()) 824 | { 825 | string strDatasetName("activity"); 826 | 827 | //Create the data space 828 | hsize_t dimension[] = { m_voAntennaStatuses.size() }; 829 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 830 | 831 | //Create a compound data type consisting of different native types per entry: 832 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cAntennaStatus)); 833 | //hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, H5T_VARIABLE); 834 | 835 | //Add to compound data type: a timestamp (double) 836 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cAntennaStatus, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 837 | 838 | //Add to compound data type: the antenna state (string) 839 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 840 | H5Tset_size(stringTypeValue, sizeof(cAntennaStatus::m_chaAntennaStatus)); 841 | H5Tinsert(compoundDataType, "value", HOFFSET(cAntennaStatus, m_chaAntennaStatus), stringTypeValue); 842 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 843 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 844 | H5Tset_size(stringTypeStatus, sizeof(cAntennaStatus::m_chaStatus)); 845 | H5Tinsert(compoundDataType, "status", HOFFSET(cAntennaStatus, m_chaStatus), stringTypeStatus); 846 | 847 | //Create the data set of of the new compound datatype 848 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 849 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voAntennaStatuses.front()); 850 | 851 | if(err < 0) 852 | { 853 | cout << "cSpectrometerHDF5OutputFile::writeAntennaStatuses(): HDF5 make dataset error" << endl; 854 | } 855 | else 856 | { 857 | cout << "cSpectrometerHDF5OutputFile::writeAntennaStatuses(): Wrote " << m_voAntennaStatuses.size() << " antenna statuses to dataset." << endl; 858 | } 859 | 860 | addAttributeToDataSet(string("Combined state of the antenna proxy"), strDatasetName, string("discrete"), string(""), dataset); 861 | 862 | H5Tclose(stringTypeStatus); 863 | H5Tclose(compoundDataType); 864 | H5Sclose(dataspace); 865 | H5Dclose(dataset); 866 | } 867 | } 868 | 869 | void cSpectrometerHDF5OutputFile::writeMotorTorques() 870 | { 871 | if (m_voMotorTorquesAzMaster_mNm.size()) 872 | { 873 | string strDatasetName("motor-torque.az-master"); 874 | 875 | //Create the data space 876 | hsize_t dimension[] = { m_voMotorTorquesAzMaster_mNm.size() }; 877 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 878 | 879 | //Create a compound data type consisting of different native types per entry: 880 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 881 | 882 | //Add to compound data type: a timestamp (double) 883 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 884 | 885 | //Add to compound data types: Torque for azimuth-master motor 886 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 887 | 888 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 889 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 890 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 891 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 892 | 893 | //Create the data set of of the new compound datatype 894 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 895 | 896 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voMotorTorquesAzMaster_mNm.front()); 897 | 898 | if(err < 0) 899 | { 900 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): HDF5 make dataset error" << endl; 901 | } 902 | else 903 | { 904 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): Wrote " << m_voMotorTorquesAzMaster_mNm.size() << " azimuth-master motor torques to dataset." << endl; 905 | } 906 | 907 | addAttributeToDataSet(string("Torques of azimuth-master motor"), strDatasetName, string("double"), string("Nm"), dataset); 908 | 909 | H5Tclose(stringTypeStatus); 910 | H5Tclose(compoundDataType); 911 | H5Sclose(dataspace); 912 | H5Dclose(dataset); 913 | } 914 | 915 | if (m_voMotorTorquesAzSlave_mNm.size()) 916 | { 917 | string strDatasetName("motor-torque.az-slave"); 918 | 919 | //Create the data space 920 | hsize_t dimension[] = { m_voMotorTorquesAzSlave_mNm.size() }; 921 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 922 | 923 | //Create a compound data type consisting of different native types per entry: 924 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 925 | 926 | //Add to compound data type: a timestamp (double) 927 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 928 | 929 | //Add to compound data types: Torque for azimuth-slave motor 930 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 931 | 932 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 933 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 934 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 935 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 936 | 937 | //Create the data set of of the new compound datatype 938 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 939 | 940 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voMotorTorquesAzSlave_mNm.front()); 941 | 942 | if(err < 0) 943 | { 944 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): HDF5 make dataset error" << endl; 945 | } 946 | else 947 | { 948 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): Wrote " << m_voMotorTorquesAzSlave_mNm.size() << " azimuth-slave motor torques to dataset." << endl; 949 | } 950 | 951 | addAttributeToDataSet(string("Torques of azimuth-slave motor"), strDatasetName, string("double"), string("Nm"), dataset); 952 | 953 | H5Tclose(stringTypeStatus); 954 | H5Tclose(compoundDataType); 955 | H5Sclose(dataspace); 956 | H5Dclose(dataset); 957 | } 958 | 959 | if (m_voMotorTorquesElMaster_mNm.size()) 960 | { 961 | string strDatasetName("motor-torque.el-master"); 962 | 963 | //Create the data space 964 | hsize_t dimension[] = { m_voMotorTorquesElMaster_mNm.size() }; 965 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 966 | 967 | //Create a compound data type consisting of different native types per entry: 968 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 969 | 970 | //Add to compound data type: a timestamp (double) 971 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 972 | 973 | //Add to compound data types: Torque for elevation-master motor 974 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 975 | 976 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 977 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 978 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 979 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 980 | 981 | //Create the data set of of the new compound datatype 982 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 983 | 984 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voMotorTorquesElMaster_mNm.front()); 985 | 986 | if(err < 0) 987 | { 988 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): HDF5 make dataset error" << endl; 989 | } 990 | else 991 | { 992 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): Wrote " << m_voMotorTorquesElMaster_mNm.size() << " elevation-master motor torques to dataset." << endl; 993 | } 994 | 995 | addAttributeToDataSet(string("Torques of elevation-master motor"), strDatasetName, string("double"), string("Nm"), dataset); 996 | 997 | H5Tclose(stringTypeStatus); 998 | H5Tclose(compoundDataType); 999 | H5Sclose(dataspace); 1000 | H5Dclose(dataset); 1001 | } 1002 | 1003 | if (m_voMotorTorquesElSlave_mNm.size()) 1004 | { 1005 | string strDatasetName("motor-torque.el-slave"); 1006 | 1007 | //Create the data space 1008 | hsize_t dimension[] = { m_voMotorTorquesElSlave_mNm.size() }; 1009 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1010 | 1011 | //Create a compound data type consisting of different native types per entry: 1012 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1013 | 1014 | //Add to compound data type: a timestamp (double) 1015 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1016 | 1017 | //Add to compound data types: Torque for elevation-slave motor 1018 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1019 | 1020 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1021 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1022 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1023 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1024 | 1025 | //Create the data set of of the new compound datatype 1026 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1027 | 1028 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voMotorTorquesElSlave_mNm.front()); 1029 | 1030 | if(err < 0) 1031 | { 1032 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): HDF5 make dataset error" << endl; 1033 | } 1034 | else 1035 | { 1036 | cout << "cSpectrometerHDF5OutputFile::writeMotorTorques(): Wrote " << m_voMotorTorquesElSlave_mNm.size() << " elevation-slave motor torques to dataset." << endl; 1037 | } 1038 | 1039 | addAttributeToDataSet(string("Torques of elevation-slave motor"), strDatasetName, string("double"), string("Nm"), dataset); 1040 | 1041 | H5Tclose(stringTypeStatus); 1042 | H5Tclose(compoundDataType); 1043 | H5Sclose(dataspace); 1044 | H5Dclose(dataset); 1045 | } 1046 | } 1047 | 1048 | void cSpectrometerHDF5OutputFile::writeAntennaConfiguration() 1049 | { 1050 | //TODO: this might be a bit naive. I suspect that there's more complexity in this than the other datasets. 1051 | if (m_vdPointingModelParams.size()) 1052 | { 1053 | hsize_t dimension = m_vdPointingModelParams.size(); 1054 | string strDatasetName("pointing-model-params"); 1055 | 1056 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationAntennasAntenna1GroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_DOUBLE, &m_vdPointingModelParams.front()); 1057 | 1058 | if(err < 0) 1059 | { 1060 | cout << "cSpectrometerHDF5OutputFile::writeAppliedPointingModel(): HDF5 make dataset error." << endl; 1061 | } 1062 | else 1063 | { 1064 | cout << "cSpectrometerHDF5OutputFile::writeAppliedPointingModel(): Wrote " << m_vdPointingModelParams.size() << " pointing model parameters to file." << endl; 1065 | } 1066 | 1067 | //Add pointing model name as data attribute 1068 | stringstream oSS; 1069 | oSS << "Pointing model name = "; 1070 | oSS << m_oAntennaConfiguration.m_chaPointModelName; 1071 | 1072 | //Need to open the dataset again here as the H5LTmake_dataset used above does leave an open handle. 1073 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationAntennasAntenna1GroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1074 | addAttributeToDataSet(oSS.str(), strDatasetName, string("string"), string(""), dataset_id); 1075 | 1076 | H5Dclose(dataset_id); 1077 | } 1078 | 1079 | if (m_vdDelayModelParams.size()) 1080 | { 1081 | hsize_t dimension = m_vdDelayModelParams.size(); 1082 | string strDatasetName("delay-model-params"); 1083 | 1084 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationAntennasAntenna1GroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_DOUBLE, &m_vdDelayModelParams.front()); 1085 | 1086 | if(err < 0) 1087 | { 1088 | cout << "cSpectrometerHDF5OutputFile::writeAntennaConfiguration(): HDF5 make dataset error." << endl; 1089 | } 1090 | else 1091 | { 1092 | cout << "cSpectrometerHDF5OutputFile::writeAntennaConfiguration(): Wrote " << m_vdDelayModelParams.size() << " delay model parameters to file." << endl; 1093 | } 1094 | } 1095 | 1096 | { 1097 | //Add the rest of the data as attributes to the group. 1098 | hid_t variableLengthStringType; 1099 | variableLengthStringType = H5Tcopy (H5T_C_S1); 1100 | 1101 | H5Tset_size (variableLengthStringType, H5T_VARIABLE); 1102 | 1103 | hid_t attrDataspace = H5Screate(H5S_SCALAR); 1104 | hid_t groupHandle = m_iH5ConfigurationAntennasAntenna1GroupHandle; // Just to keep the lines a bit shorter. 1105 | 1106 | hid_t attrAntennaName = H5Acreate(groupHandle, "name", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 1107 | const char* pcAntennaName = m_oAntennaConfiguration.m_chaAntennaName; 1108 | H5Awrite(attrAntennaName, variableLengthStringType, &pcAntennaName); 1109 | 1110 | hid_t attrAntennaDiameter = H5Acreate(groupHandle, "diameter", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 1111 | const char* pcAntennaDiameter_m = m_oAntennaConfiguration.m_chaAntennaDiameter_m; 1112 | H5Awrite(attrAntennaDiameter, variableLengthStringType, &pcAntennaDiameter_m); 1113 | 1114 | hid_t attrAntennaBeamwidth = H5Acreate(groupHandle, "beamwidth", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 1115 | const char* pcAntennaBeamwidth_deg = m_oAntennaConfiguration.m_chaAntennaBeamwidth; 1116 | H5Awrite(attrAntennaBeamwidth, variableLengthStringType, &pcAntennaBeamwidth_deg); 1117 | 1118 | hid_t attrAntennaLatitude = H5Acreate(groupHandle, "latitude", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 1119 | const char* pcAntennaLatitude_deg = m_oAntennaConfiguration.m_chaAntennaLatitude_deg; 1120 | H5Awrite(attrAntennaLatitude, variableLengthStringType, &pcAntennaLatitude_deg); 1121 | 1122 | hid_t attrAntennaLongitude = H5Acreate(groupHandle, "longitude", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 1123 | const char* pcAntennaLongitude_deg = m_oAntennaConfiguration.m_chaAntennaLongitude_deg; 1124 | H5Awrite(attrAntennaLongitude, variableLengthStringType, &pcAntennaLongitude_deg); 1125 | 1126 | hid_t attrAntennaAltitude = H5Acreate(groupHandle, "altitude", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 1127 | const char* pcAntennaAltitude_m = m_oAntennaConfiguration.m_chaAntennaAltitude_m; 1128 | H5Awrite(attrAntennaAltitude, variableLengthStringType, &pcAntennaAltitude_m); 1129 | 1130 | H5Aclose(attrAntennaAltitude); 1131 | H5Aclose(attrAntennaBeamwidth); 1132 | H5Aclose(attrAntennaDiameter); 1133 | H5Aclose(attrAntennaLatitude); 1134 | H5Aclose(attrAntennaLongitude); 1135 | H5Aclose(attrAntennaName); 1136 | H5Tclose(variableLengthStringType); 1137 | H5Sclose(attrDataspace); 1138 | } 1139 | } 1140 | 1141 | void cSpectrometerHDF5OutputFile::writeNoiseDiodeSoftwareStates() 1142 | { 1143 | //TODO: Figure out what to do with this. 1144 | if (m_voNoiseDiodeSoftwareStates.size()) 1145 | { 1146 | string strDatasetName("noise-diode.software.on"); 1147 | 1148 | //Create the data space 1149 | hsize_t dimension[] = { m_voNoiseDiodeSoftwareStates.size() }; 1150 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1151 | 1152 | //Create a compound data type consisting of different native types per entry: 1153 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedChar)); 1154 | 1155 | //Add to compound data type: a timestamp (double) 1156 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedChar, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1157 | 1158 | //Add to compound data type: the noise diode state (string of 1 character "0" or "1") 1159 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 1160 | H5Tset_size(stringTypeValue, sizeof(cTimestampedChar::m_chaValue)); 1161 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedChar, m_chaValue), stringTypeValue); 1162 | 1163 | //Add to compound data type: the status of the noise diode equiptment (string typically containing "nominal") 1164 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1165 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedChar::m_chaStatus)); 1166 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedChar, m_chaStatus), stringTypeStatus); 1167 | 1168 | //Create the data set of of the new compound datatype 1169 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1170 | 1171 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voNoiseDiodeSoftwareStates.front()); 1172 | 1173 | if(err < 0) 1174 | { 1175 | cout << "cSpectrometerHDF5OutputFile::writeNoiseDiodeSoftwareStates(): HDF5 make dataset error" << endl; 1176 | } 1177 | else 1178 | { 1179 | cout << "cSpectrometerHDF5OutputFile::writeNoiseDiodeSoftwareStates(): Wrote " << m_voNoiseDiodeSoftwareStates.size() << " noise diode states to dataset." << endl; 1180 | } 1181 | 1182 | addAttributeToDataSet(string("software controlled noise diode state"), strDatasetName, string("boolean"), string(""), dataset); 1183 | 1184 | H5Tclose(stringTypeValue); 1185 | H5Tclose(stringTypeStatus); 1186 | H5Tclose(compoundDataType); 1187 | H5Sclose(dataspace); 1188 | H5Dclose(dataset); 1189 | } 1190 | } 1191 | 1192 | void cSpectrometerHDF5OutputFile::writeNoiseDiodeSources() 1193 | { 1194 | if (m_voNoiseDiodeSources.size()) 1195 | { 1196 | string strDatasetName("noise-diode.source"); 1197 | 1198 | //Create the data space 1199 | hsize_t dimension[] = { m_voNoiseDiodeSources.size() }; 1200 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1201 | 1202 | //Create a compound data type consisting of different native types per entry: 1203 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cNoiseDiodeSource)); 1204 | 1205 | //Add to compound data type: a timestamp (double) 1206 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cNoiseDiodeSource, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1207 | 1208 | //Add to compound data type: the noise diode source (c string) 1209 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 1210 | H5Tset_size(stringTypeValue, sizeof(cNoiseDiodeSource::m_chaSource)); 1211 | H5Tinsert(compoundDataType, "value", HOFFSET(cNoiseDiodeSource, m_chaSource), stringTypeValue); 1212 | 1213 | //Add to compound data type: the status of the noise diode equiptment (string typically containing "nominal") 1214 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1215 | H5Tset_size(stringTypeStatus, sizeof(cNoiseDiodeSource::m_chaStatus)); 1216 | H5Tinsert(compoundDataType, "status", HOFFSET(cNoiseDiodeSource, m_chaStatus), stringTypeStatus); 1217 | 1218 | //Create the data set of of the new compound datatype 1219 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1220 | 1221 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voNoiseDiodeSources.front()); 1222 | 1223 | if(err < 0) 1224 | { 1225 | cout << "cSpectrometerHDF5OutputFile::writeNoiseDiodeSources(): HDF5 make dataset error" << endl; 1226 | } 1227 | else 1228 | { 1229 | cout << "cSpectrometerHDF5OutputFile::writeNoiseDiodeSources(): Wrote " << m_voNoiseDiodeSources.size() << " noise diode sources to dataset." << endl; 1230 | } 1231 | 1232 | addAttributeToDataSet(string("source of noise diode control"), strDatasetName, string("discrete"), string(""), dataset); 1233 | 1234 | H5Tclose(stringTypeValue); 1235 | H5Tclose(stringTypeStatus); 1236 | H5Tclose(compoundDataType); 1237 | H5Sclose(dataspace); 1238 | H5Dclose(dataset); 1239 | } 1240 | } 1241 | 1242 | void cSpectrometerHDF5OutputFile::writeNoideDiodeCurrents() 1243 | { 1244 | if (m_voNoiseDiodeCurrents.size()) 1245 | { 1246 | string strDatasetName("noise-diode.current"); 1247 | 1248 | //Create the data space 1249 | hsize_t dimension[] = { m_voNoiseDiodeCurrents.size() }; 1250 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1251 | 1252 | //Create a compound data type consisting of different native types per entry: 1253 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1254 | 1255 | //Add to compound data type: a timestamp (double) 1256 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1257 | 1258 | //Add to compound data type: the noise diode current (double) 1259 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1260 | 1261 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1262 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1263 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedChar::m_chaStatus)); 1264 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1265 | 1266 | //Create the data set of of the new compound datatype 1267 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1268 | 1269 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voNoiseDiodeCurrents.front()); 1270 | 1271 | if(err < 0) 1272 | { 1273 | cout << "cSpectrometerHDF5OutputFile::writeNoideDiodeCurrents(): HDF5 make dataset error" << endl; 1274 | } 1275 | else 1276 | { 1277 | cout << "cSpectrometerHDF5OutputFile::writeNoideDiodeCurrents(): Wrote " << m_voNoiseDiodeCurrents.size() << " noise diode currents to dataset." << endl; 1278 | } 1279 | 1280 | addAttributeToDataSet(string("current draw of noise diode"), strDatasetName, string("double"), string("A"), dataset); 1281 | 1282 | H5Tclose(stringTypeStatus); 1283 | H5Tclose(compoundDataType); 1284 | H5Sclose(dataspace); 1285 | H5Dclose(dataset); 1286 | } 1287 | } 1288 | 1289 | void cSpectrometerHDF5OutputFile::writeSelectedSources() 1290 | { 1291 | if (m_voSelectedSources.size()) 1292 | { 1293 | string strDatasetName("target"); 1294 | 1295 | //Create the data space 1296 | hsize_t dimension[] = { m_voSelectedSources.size() }; 1297 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1298 | 1299 | //Create a compound data type consisting of different native types per entry: 1300 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cSourceSelection)); 1301 | 1302 | //Add to compound data type: a timestamp (double) 1303 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cSourceSelection, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1304 | 1305 | //Add to compound data type: the source name and ra/dec (c string) 1306 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 1307 | H5Tset_size(stringTypeValue, sizeof(cSourceSelection::m_chaSource)); 1308 | H5Tinsert(compoundDataType, "value", HOFFSET(cSourceSelection, m_chaSource), stringTypeValue); 1309 | 1310 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1311 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1312 | H5Tset_size(stringTypeStatus, sizeof(cSourceSelection::m_chaStatus)); 1313 | H5Tinsert(compoundDataType, "status", HOFFSET(cSourceSelection, m_chaStatus), stringTypeStatus); 1314 | 1315 | //Create the data set of of the new compound datatype 1316 | hid_t dataset = H5Dcreate1(m_iH5SensorsAntennasAntenna1GroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1317 | 1318 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voSelectedSources.front()); 1319 | 1320 | if(err < 0) 1321 | { 1322 | cout << "cSpectrometerHDF5OutputFile::writeSelectedSources(): HDF5 make dataset error" << endl; 1323 | } 1324 | else 1325 | { 1326 | cout << "cSpectrometerHDF5OutputFile::writeSelectedSources(): Wrote " << m_voSelectedSources.size() << " astronomical sources to dataset." << endl; 1327 | } 1328 | 1329 | addAttributeToDataSet(string("target"), strDatasetName, string("string"), string(""), dataset); 1330 | 1331 | H5Tclose(stringTypeValue); 1332 | H5Tclose(stringTypeStatus); 1333 | H5Tclose(compoundDataType); 1334 | H5Sclose(dataspace); 1335 | H5Dclose(dataset); 1336 | } 1337 | } 1338 | 1339 | void cSpectrometerHDF5OutputFile::writeRFFrequencies() 1340 | { 1341 | if (m_voFrequencySelectLCP.size()) 1342 | { 1343 | string strDatasetName("rfe.band.select.LCP"); 1344 | 1345 | //Create the data space 1346 | hsize_t dimension[] = { m_voFrequencySelectLCP.size() }; 1347 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1348 | 1349 | //Create a compound data type consisting of different native types per entry: 1350 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1351 | 1352 | //Add to compound data type: a timestamp (double) 1353 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1354 | 1355 | //Add to compound data type: the FrequencySelectLCP state (string of 1 character "0" or "1") 1356 | // Zero means 5 GHz, 1 means 6.7 GHz. 1357 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 1358 | H5Tset_size(stringTypeValue, sizeof(cTimestampedChar::m_chaValue)); 1359 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedChar, m_chaValue), stringTypeValue); 1360 | 1361 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1362 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1363 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedChar::m_chaStatus)); 1364 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedChar, m_chaStatus), stringTypeStatus); 1365 | 1366 | //Create the data set of of the new compound datatype 1367 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1368 | 1369 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voFrequencySelectLCP.front()); 1370 | 1371 | if(err < 0) 1372 | { 1373 | cout << "cSpectrometerHDF5OutputFile::writeRFFrequencies(): HDF5 make dataset error" << endl; 1374 | } 1375 | else 1376 | { 1377 | cout << "cSpectrometerHDF5OutputFile::writeRFFrequencies(): Wrote " << m_voFrequencySelectLCP.size() << " RF band selections for LCP." << endl; 1378 | } 1379 | 1380 | addAttributeToDataSet(string("RF band selection for LCP (0 - 5GHz, 1 - 6.7 GHz)"), strDatasetName, string("boolean"), string(""), dataset); 1381 | 1382 | H5Tclose(stringTypeValue); 1383 | H5Tclose(stringTypeStatus); 1384 | H5Tclose(compoundDataType); 1385 | H5Sclose(dataspace); 1386 | H5Dclose(dataset); 1387 | } 1388 | 1389 | if (m_voFrequencySelectRCP.size()) 1390 | { 1391 | string strDatasetName("rfe.band.select.RCP"); 1392 | 1393 | //Create the data space 1394 | hsize_t dimension[] = { m_voFrequencySelectRCP.size() }; 1395 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1396 | 1397 | //Create a compound data type consisting of different native types per entry: 1398 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1399 | 1400 | //Add to compound data type: a timestamp (double) 1401 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1402 | 1403 | //Add to compound data type: the FrequencySelectLCP state (string of 1 character "0" or "1") 1404 | // Zero means 5 GHz, 1 means 6.7 GHz. 1405 | hid_t stringTypeValue = H5Tcopy (H5T_C_S1); 1406 | H5Tset_size(stringTypeValue, sizeof(cTimestampedChar::m_chaValue)); 1407 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedChar, m_chaValue), stringTypeValue); 1408 | 1409 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1410 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1411 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedChar::m_chaStatus)); 1412 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedChar, m_chaStatus), stringTypeStatus); 1413 | 1414 | //Create the data set of of the new compound datatype 1415 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1416 | 1417 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voFrequencySelectRCP.front()); 1418 | 1419 | if(err < 0) 1420 | { 1421 | cout << "cSpectrometerHDF5OutputFile::writeRFFrequencies(): HDF5 make dataset error" << endl; 1422 | } 1423 | else 1424 | { 1425 | cout << "cSpectrometerHDF5OutputFile::writeRFFrequencies(): Wrote " << m_voFrequencySelectLCP.size() << " RF band selections for RCP." << endl; 1426 | } 1427 | 1428 | addAttributeToDataSet(string("RF band selection for LCP (0 - 5GHz, 1 - 6.7 GHz)"), strDatasetName, string("boolean"), string(""), dataset); 1429 | 1430 | H5Tclose(stringTypeValue); 1431 | H5Tclose(stringTypeStatus); 1432 | H5Tclose(compoundDataType); 1433 | H5Sclose(dataspace); 1434 | H5Dclose(dataset); 1435 | } 1436 | } 1437 | 1438 | void cSpectrometerHDF5OutputFile::writeLOFrequencies() 1439 | { 1440 | if (m_voFrequenciesLO0Chan0_Hz.size()) 1441 | { 1442 | string strDatasetName("rfe.lo0.chan0.frequency"); // chan 0 is the 5 GHz receiver 1443 | 1444 | //Create the data space 1445 | hsize_t dimension[] = { m_voFrequenciesLO0Chan0_Hz.size() }; 1446 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1447 | 1448 | //Create a compound data type consisting of different native types per entry: 1449 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1450 | 1451 | //Add to compound data type: a timestamp (double) 1452 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1453 | 1454 | //Add to compound data type: the chan 0 LO0 frequency (double) 1455 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1456 | 1457 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1458 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1459 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1460 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1461 | 1462 | //Create the data set of of the new compound datatype 1463 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1464 | 1465 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voFrequenciesLO0Chan0_Hz.front()); 1466 | 1467 | if(err < 0) 1468 | { 1469 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): HDF5 make dataset error" << endl; 1470 | } 1471 | else 1472 | { 1473 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): Wrote " << m_voFrequenciesLO0Chan0_Hz.size() << " LO0 chan 0 frequencies." << endl; 1474 | } 1475 | 1476 | addAttributeToDataSet(string("frequency of synth a, valon 0 (5 GHz LO)"), strDatasetName, string("double"), string("Hz"), dataset); 1477 | 1478 | H5Tclose(stringTypeStatus); 1479 | H5Tclose(compoundDataType); 1480 | H5Sclose(dataspace); 1481 | H5Dclose(dataset); 1482 | } 1483 | 1484 | if (m_voFrequenciesLO0Chan1_Hz.size()) 1485 | { 1486 | string strDatasetName("rfe.lo0.chan1.frequency"); // chan1 is the 6.7 GHz receiver 1487 | 1488 | //Create the data space 1489 | hsize_t dimension[] = { m_voFrequenciesLO0Chan1_Hz.size() }; 1490 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1491 | 1492 | //Create a compound data type consisting of different native types per entry: 1493 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1494 | 1495 | //Add to compound data type: a timestamp (double) 1496 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1497 | 1498 | //Add to compound data type: the chan 1 LO0 frequency (double) 1499 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1500 | 1501 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1502 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1503 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1504 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1505 | 1506 | //Create the data set of of the new compound datatype 1507 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1508 | 1509 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voFrequenciesLO0Chan1_Hz.front()); 1510 | 1511 | if(err < 0) 1512 | { 1513 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): HDF5 make dataset error" << endl; 1514 | } 1515 | else 1516 | { 1517 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): Wrote " << m_voFrequenciesLO0Chan1_Hz.size() << " LO0 chan 1 frequencies." << endl; 1518 | } 1519 | 1520 | addAttributeToDataSet(string("frequency of synth b, valon 0 (6.7 GHz LO)"), strDatasetName, string("double"), string("Hz"), dataset); 1521 | 1522 | H5Tclose(stringTypeStatus); 1523 | H5Tclose(compoundDataType); 1524 | H5Sclose(dataspace); 1525 | H5Dclose(dataset); 1526 | } 1527 | 1528 | if (m_voFrequenciesLO1_Hz.size()) 1529 | { 1530 | string strDatasetName("rfe.lo1.frequency"); 1531 | 1532 | //Create the data space 1533 | hsize_t dimension[] = { m_voFrequenciesLO1_Hz.size() }; 1534 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1535 | 1536 | //Create a compound data type consisting of different native types per entry: 1537 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1538 | 1539 | //Add to compound data type: a timestamp (double) 1540 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1541 | 1542 | //Add to compound data type: the LO1 frequency (double) 1543 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1544 | 1545 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1546 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1547 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1548 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1549 | 1550 | //Create the data set of of the new compound datatype 1551 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1552 | 1553 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voFrequenciesLO1_Hz.front()); 1554 | 1555 | if(err < 0) 1556 | { 1557 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): HDF5 make dataset error" << endl; 1558 | } 1559 | else 1560 | { 1561 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): Wrote " << m_voFrequenciesLO1_Hz.size() << " LO1 frequencies." << endl; 1562 | } 1563 | 1564 | addAttributeToDataSet(string("frequency of valon 1 synth a (Intermediate LO)"), strDatasetName, string("double"), string("Hz"), dataset); 1565 | 1566 | H5Tclose(stringTypeStatus); 1567 | H5Tclose(compoundDataType); 1568 | H5Sclose(dataspace); 1569 | H5Dclose(dataset); 1570 | } 1571 | } 1572 | 1573 | void cSpectrometerHDF5OutputFile::writeIFBandwidths() 1574 | { 1575 | if (m_voReceiverBandwidthsChan0_Hz.size()) 1576 | { 1577 | string strDatasetName("rfe.if.chan0.receiver_bandwidth"); 1578 | 1579 | //Create the data space 1580 | hsize_t dimension[] = { m_voReceiverBandwidthsChan0_Hz.size() }; 1581 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1582 | 1583 | //Create a compound data type consisting of different native types per entry: 1584 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1585 | 1586 | //Add to compound data type: a timestamp (double) 1587 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1588 | 1589 | //Add to compound data type: the receiver bandwidth (double) 1590 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1591 | 1592 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1593 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1594 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1595 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1596 | 1597 | //Create the data set of of the new compound datatype 1598 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1599 | 1600 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voReceiverBandwidthsChan0_Hz.front()); 1601 | 1602 | if(err < 0) 1603 | { 1604 | cout << "cSpectrometerHDF5OutputFile::writeIFBandwidths(): HDF5 make dataset error" << endl; 1605 | } 1606 | else 1607 | { 1608 | cout << "cSpectrometerHDF5OutputFile::writeIFBandwidths(): Wrote " << m_voReceiverBandwidthsChan0_Hz.size() << " chan0 receiver bandwidths." << endl; 1609 | } 1610 | 1611 | addAttributeToDataSet(string("Analogue 3 dB bandwidth available to the ADC chan0"), strDatasetName, string("double"), string("Hz"), dataset); 1612 | 1613 | H5Tclose(stringTypeStatus); 1614 | H5Tclose(compoundDataType); 1615 | H5Sclose(dataspace); 1616 | H5Dclose(dataset); 1617 | } 1618 | 1619 | if (m_voReceiverBandwidthsChan1_Hz.size()) 1620 | { 1621 | string strDatasetName("rfe.if.chan1.receiver_bandwidth"); 1622 | 1623 | //Create the data space 1624 | hsize_t dimension[] = { m_voReceiverBandwidthsChan1_Hz.size() }; 1625 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1626 | 1627 | //Create a compound data type consisting of different native types per entry: 1628 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1629 | 1630 | //Add to compound data type: a timestamp (double) 1631 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1632 | 1633 | //Add to compound data type: the receiver bandwidth (double) 1634 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1635 | 1636 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1637 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1638 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1639 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1640 | 1641 | //Create the data set of of the new compound datatype 1642 | hid_t dataset = H5Dcreate1(m_iH5SensorsRFEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1643 | 1644 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voReceiverBandwidthsChan1_Hz.front()); 1645 | 1646 | if(err < 0) 1647 | { 1648 | cout << "cSpectrometerHDF5OutputFile::writeIFBandwidths(): HDF5 make dataset error" << endl; 1649 | } 1650 | else 1651 | { 1652 | cout << "cSpectrometerHDF5OutputFile::writeIFBandwidths(): Wrote " << m_voReceiverBandwidthsChan1_Hz.size() << " chan1 receiver bandwidths." << endl; 1653 | } 1654 | 1655 | addAttributeToDataSet(string("Analogue 3 dB bandwidth available to the ADC chan1"), strDatasetName, string("double"), string("Hz"), dataset); 1656 | 1657 | H5Tclose(stringTypeStatus); 1658 | H5Tclose(compoundDataType); 1659 | H5Sclose(dataspace); 1660 | H5Dclose(dataset); 1661 | } 1662 | } 1663 | 1664 | void cSpectrometerHDF5OutputFile::writeROACHNumberChannels() 1665 | { 1666 | hsize_t dimension = 1; 1667 | string strDatasetName("n_chans"); 1668 | 1669 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_UINT32, &m_u32NFrequencyBins); 1670 | 1671 | if(err < 0) 1672 | { 1673 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFrequency(): HDF5 make dataset error." << endl; 1674 | } 1675 | else 1676 | { 1677 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFrequency(): Wrote number of channels." << endl; 1678 | } 1679 | 1680 | //Need to open the dataset again here for attribute as the H5LTmake_dataset used above does leave an open handle. 1681 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1682 | addAttributeToDataSet(string("Number of frequency channels"), strDatasetName, string("uint32"), string(""), dataset_id); 1683 | 1684 | H5Dclose(dataset_id); 1685 | } 1686 | 1687 | void cSpectrometerHDF5OutputFile::writeROACHAccumulationLengths() 1688 | { 1689 | //Ideally this dataset should only be one element long. So we'll trim. 1690 | //TODO: This might not be the case. Should we be able to adjust dynamically? Check with Ludwig. 1691 | vector voUniqueAccumulationLengths_nFrames; 1692 | uint32_t ui32CurrentAccumulationLength_nFrames = 0; 1693 | for (uint32_t ui = 0; ui < m_voROACHAccumulationLengths_nFrames.size(); ui++) 1694 | { 1695 | if (m_voROACHAccumulationLengths_nFrames[ui].m_u32Value != ui32CurrentAccumulationLength_nFrames) 1696 | { 1697 | ui32CurrentAccumulationLength_nFrames = m_voROACHAccumulationLengths_nFrames[ui].m_u32Value; 1698 | voUniqueAccumulationLengths_nFrames.push_back(m_voROACHAccumulationLengths_nFrames[ui]); 1699 | } 1700 | } 1701 | 1702 | hsize_t dimension = 1; 1703 | string strDatasetName("accum_length"); 1704 | 1705 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_UINT32, &ui32CurrentAccumulationLength_nFrames); 1706 | 1707 | if(err < 0) 1708 | { 1709 | cout << "cSpectrometerHDF5OutputFile::writeROACHAccumulationLengths(): HDF5 make dataset error." << endl; 1710 | } 1711 | else 1712 | { 1713 | cout << "cSpectrometerHDF5OutputFile::writeROACHAccumulationLengths(): Wrote accumulation length." << endl; 1714 | } 1715 | 1716 | //Need to open the dataset again here for attribute as the H5LTmake_dataset used above does leave an open handle. 1717 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1718 | addAttributeToDataSet(string("number of PFB/FFT frames accumulated by the ROACH."), strDatasetName, string("double"), string("frames"), dataset_id); 1719 | 1720 | H5Dclose(dataset_id); 1721 | 1722 | if (0) // (voUniqueAccumulationLengths_nFrames.size() != 1) 1723 | { 1724 | cout << "Warning! Unexpected change in accumulation length during recording. Saving changes in additional sensor dataset." << endl; 1725 | 1726 | string strDatasetName("accum_length_history"); 1727 | 1728 | //Create the data space 1729 | hsize_t dimension[] = { voUniqueAccumulationLengths_nFrames.size() }; 1730 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1731 | 1732 | //Create a compound data type consisting of different native types per entry: 1733 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedUnsignedInt)); 1734 | 1735 | //Add to compound data type: a timestamp (double) 1736 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedUnsignedInt, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1737 | 1738 | //Add to compound data type: the accumulation length (unsigned int) 1739 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedUnsignedInt, m_u32Value), H5T_NATIVE_UINT32); 1740 | 1741 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1742 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1743 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedUnsignedInt::m_chaStatus)); 1744 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedUnsignedInt, m_chaStatus), stringTypeStatus); 1745 | 1746 | //Create the data set of of the new compound datatype 1747 | hid_t dataset = H5Dcreate1(m_iH5SensorsDBEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1748 | 1749 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &voUniqueAccumulationLengths_nFrames.front()); 1750 | 1751 | if(err < 0) 1752 | { 1753 | cout << "cSpectrometerHDF5OutputFile::writeROACHAccumulationLengths(): HDF5 make dataset error" << endl; 1754 | } 1755 | else 1756 | { 1757 | cout << "cSpectrometerHDF5OutputFile::writeROACHAccumulationLengths(): Wrote " << voUniqueAccumulationLengths_nFrames.size() << " accumulation lengths." << endl; 1758 | } 1759 | 1760 | addAttributeToDataSet(string("accumulation length"), strDatasetName, string("unsigned int"), string("no. of FFT frames"), dataset); 1761 | 1762 | H5Tclose(stringTypeStatus); 1763 | H5Tclose(compoundDataType); 1764 | H5Sclose(dataspace); 1765 | H5Dclose(dataset); 1766 | } 1767 | } 1768 | 1769 | 1770 | void cSpectrometerHDF5OutputFile::writeROACHNBNarrowbandSelections() 1771 | { 1772 | if (m_voROACHNBChannelSelects.size()) 1773 | { 1774 | string strDatasetName("dbe.nb-chan"); 1775 | 1776 | //Create the data space 1777 | hsize_t dimension[] = { m_voROACHNBChannelSelects.size() }; 1778 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1779 | 1780 | //Create a compound data type consisting of different native types per entry: 1781 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedUnsignedInt)); 1782 | 1783 | //Add to compound data type: a timestamp (double) 1784 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedUnsignedInt, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1785 | 1786 | //Add to compound data type: the narrowband channel no (unsigned int) 1787 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedUnsignedInt, m_u32Value), H5T_NATIVE_UINT32); 1788 | 1789 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1790 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1791 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedUnsignedInt::m_chaStatus)); 1792 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedUnsignedInt, m_chaStatus), stringTypeStatus); 1793 | 1794 | //Create the data set of of the new compound datatype 1795 | hid_t dataset = H5Dcreate1(m_iH5SensorsDBEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1796 | 1797 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voROACHNBChannelSelects.front()); 1798 | 1799 | if(err < 0) 1800 | { 1801 | cout << "cSpectrometerHDF5OutputFile::writeROACHNBNarrowbandSelections(): HDF5 make dataset error" << endl; 1802 | } 1803 | else 1804 | { 1805 | cout << "cSpectrometerHDF5OutputFile::writeROACHNBNarrowbandSelections(): Wrote " << m_voROACHNBChannelSelects.size() << " narrow band channel selections." << endl; 1806 | } 1807 | 1808 | addAttributeToDataSet(string("narrowband channel selection"), strDatasetName, string("unsigned int"), string("cannonical bin no."), dataset); 1809 | 1810 | H5Tclose(stringTypeStatus); 1811 | H5Tclose(compoundDataType); 1812 | H5Sclose(dataspace); 1813 | H5Dclose(dataset); 1814 | } 1815 | } 1816 | 1817 | void cSpectrometerHDF5OutputFile::writeROACHSamplingFreqBandwidth() 1818 | { 1819 | { 1820 | hsize_t dimension = 1; 1821 | string strDatasetName("adc_clk"); 1822 | 1823 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_DOUBLE, &m_dROACHFrequencyFs_Hz); 1824 | 1825 | if(err < 0) 1826 | { 1827 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFreqBandwidth(): HDF5 make dataset error." << endl; 1828 | } 1829 | else 1830 | { 1831 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFreqBandwidth(): Wrote ADC Sampling frequency." << endl; 1832 | } 1833 | 1834 | //Need to open the dataset again here for attribute as the H5LTmake_dataset used above does leave an open handle. 1835 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1836 | addAttributeToDataSet(string("sampling frequency of ROACH / KatADC"), strDatasetName, string("double"), string("Hz"), dataset_id); 1837 | 1838 | H5Dclose(dataset_id); 1839 | } 1840 | 1841 | { 1842 | //Calculate the 'digital' bandwidth of the file. Wideband / radiometer mode assumed to be default. 1843 | double iBandwidth_Hz = m_dROACHFrequencyFs_Hz / 2.0; 1844 | if (m_u32ROACHSizeOfFineFFT_nSamp) 1845 | { 1846 | //If the fineFFT size is nonzero, then it's a narrowband mode. 1847 | //Bandwidth is reduced by a factor of the number of coarse channels, 1848 | //which is in turn the number of points divided by 2. 1849 | int iNumCoarseChannels_nChan = m_u32ROACHSizeOfCoarseFFT_nSamp / 2; 1850 | iBandwidth_Hz = iBandwidth_Hz / iNumCoarseChannels_nChan; 1851 | } 1852 | 1853 | hsize_t dimension = 1; 1854 | string strDatasetName("bandwidth"); 1855 | 1856 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_DOUBLE, &iBandwidth_Hz); 1857 | 1858 | if(err < 0) 1859 | { 1860 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFreqBandwidth(): HDF5 make dataset error." << endl; 1861 | } 1862 | else 1863 | { 1864 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFreqBandwidth(): Wrote observation bandwidth." << endl; 1865 | } 1866 | 1867 | //Need to open the dataset again here for attribute as the H5LTmake_dataset used above does leave an open handle. 1868 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1869 | addAttributeToDataSet(string("Bandwidth of observation"), strDatasetName, string("double"), string("Hz"), dataset_id); 1870 | 1871 | H5Dclose(dataset_id); 1872 | } 1873 | } 1874 | 1875 | void cSpectrometerHDF5OutputFile::writeROACHSizeOfFFTs() 1876 | { 1877 | { 1878 | hsize_t dimension = 1; 1879 | string strDatasetName("dbe.fft.coarse.size"); 1880 | 1881 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_UINT32, &m_u32ROACHSizeOfCoarseFFT_nSamp); 1882 | 1883 | if(err < 0) 1884 | { 1885 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFrequency(): HDF5 make dataset error." << endl; 1886 | } 1887 | else 1888 | { 1889 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFrequency(): Wrote coarse FFT size: " << m_u32ROACHSizeOfCoarseFFT_nSamp << endl; 1890 | } 1891 | 1892 | //Need to open the dataset again here for attribute as the H5LTmake_dataset used above does leave an open handle. 1893 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1894 | addAttributeToDataSet(string("size of coarse FFT"), strDatasetName, string("unsigned int"), string("no. of time domain input samples"), dataset_id); 1895 | 1896 | H5Dclose(dataset_id); 1897 | } 1898 | 1899 | { 1900 | hsize_t dimension = 1; 1901 | string strDatasetName("dbe.fft.fine.size"); 1902 | 1903 | herr_t err = H5LTmake_dataset(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), 1, &dimension, H5T_NATIVE_UINT32, &m_u32ROACHSizeOfFineFFT_nSamp); 1904 | 1905 | if(err < 0) 1906 | { 1907 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFrequency(): HDF5 make dataset error." << endl; 1908 | } 1909 | else 1910 | { 1911 | cout << "cSpectrometerHDF5OutputFile::writeROACHSamplingFrequency(): Wrote fine FFT size: " << m_u32ROACHSizeOfFineFFT_nSamp << endl; 1912 | } 1913 | 1914 | //Need to open the dataset again here for attribute as the H5LTmake_dataset used above does leave an open handle. 1915 | hid_t dataset_id = H5Dopen2(m_iH5ConfigurationDBEGroupHandle, strDatasetName.c_str(), H5P_DEFAULT); 1916 | addAttributeToDataSet(string("size of fine FFT"), strDatasetName, string("unsigned int"), string("no. of time domain input samples"), dataset_id); 1917 | 1918 | H5Dclose(dataset_id); 1919 | } 1920 | } 1921 | 1922 | void cSpectrometerHDF5OutputFile::writeROACHCoarseFFTShiftMask() 1923 | { 1924 | string strDatasetName("dbe.coarse-fft-shift-mask"); 1925 | 1926 | //Create the data space 1927 | hsize_t dimension[] = { m_voROACHCoarseFFTShiftMasks.size() }; 1928 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1929 | 1930 | //Create a compound data type consisting of different native types per entry: 1931 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedUnsignedInt)); 1932 | 1933 | //Add to compound data type: a timestamp (double) 1934 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedUnsignedInt, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1935 | 1936 | //Add to compound data type: the shift mask applied to the coarse FFT no (unsigned int) 1937 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedUnsignedInt, m_u32Value), H5T_NATIVE_UINT32); 1938 | 1939 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1940 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1941 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedUnsignedInt::m_chaStatus)); 1942 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedUnsignedInt, m_chaStatus), stringTypeStatus); 1943 | 1944 | //Create the data set of of the new compound datatype 1945 | hid_t dataset = H5Dcreate1(m_iH5SensorsDBEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1946 | 1947 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voROACHCoarseFFTShiftMasks.front()); 1948 | 1949 | if(err < 0) 1950 | { 1951 | cout << "cSpectrometerHDF5OutputFile::writeROACHCoarseFFTShiftMask(): HDF5 make dataset error" << endl; 1952 | } 1953 | else 1954 | { 1955 | cout << "cSpectrometerHDF5OutputFile::writeROACHCoarseFFTShiftMask(): Wrote " << m_voROACHCoarseFFTShiftMasks.size() << " coarse FFT shift masks." << endl; 1956 | } 1957 | 1958 | addAttributeToDataSet(string("the shift mask applied to the coarse FFT"), strDatasetName, string("unsigned int"), string(""), dataset); 1959 | 1960 | H5Tclose(stringTypeStatus); 1961 | H5Tclose(compoundDataType); 1962 | H5Sclose(dataspace); 1963 | H5Dclose(dataset); 1964 | } 1965 | 1966 | void cSpectrometerHDF5OutputFile::writeROACHAdcAttentuations() 1967 | { 1968 | { 1969 | string strDatasetName("dbe.adc.chan0.attenuation"); 1970 | 1971 | //Create the data space 1972 | hsize_t dimension[] = { m_voROACHADCAttenuationsChan0_dB.size() }; 1973 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 1974 | 1975 | //Create a compound data type consisting of different native types per entry: 1976 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 1977 | 1978 | //Add to compound data type: a timestamp (double) 1979 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 1980 | 1981 | //Add to compound data type: the ADC attenuation (double) 1982 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 1983 | 1984 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 1985 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 1986 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 1987 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 1988 | 1989 | //Create the data set of of the new compound datatype 1990 | hid_t dataset = H5Dcreate1(m_iH5SensorsDBEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 1991 | 1992 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voROACHADCAttenuationsChan0_dB.front()); 1993 | 1994 | if(err < 0) 1995 | { 1996 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): HDF5 make dataset error" << endl; 1997 | } 1998 | else 1999 | { 2000 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): Wrote " << m_voROACHADCAttenuationsChan0_dB.size() << " ADC attenuations for chan0." << endl; 2001 | } 2002 | 2003 | addAttributeToDataSet(string("attenuation at input to ADC chan0"), strDatasetName, string("double"), string("dB"), dataset); 2004 | 2005 | H5Tclose(stringTypeStatus); 2006 | H5Tclose(compoundDataType); 2007 | H5Sclose(dataspace); 2008 | H5Dclose(dataset); 2009 | } 2010 | 2011 | { 2012 | string strDatasetName("dbe.adc.chan1.attenuation"); 2013 | 2014 | //Create the data space 2015 | hsize_t dimension[] = { m_voROACHADCAttenuationsChan1_dB.size() }; 2016 | hid_t dataspace = H5Screate_simple(1, dimension, NULL); // 1 = 1 dimensional 2017 | 2018 | //Create a compound data type consisting of different native types per entry: 2019 | hid_t compoundDataType = H5Tcreate (H5T_COMPOUND, sizeof(cTimestampedDouble)); 2020 | 2021 | //Add to compound data type: a timestamp (double) 2022 | H5Tinsert(compoundDataType, "timestamp", HOFFSET(cTimestampedDouble, m_dTimestamp_s), H5T_NATIVE_DOUBLE); 2023 | 2024 | //Add to compound data type: the ADC attenuation (double) 2025 | H5Tinsert(compoundDataType, "value", HOFFSET(cTimestampedDouble, m_dValue), H5T_NATIVE_DOUBLE); 2026 | 2027 | //Add to compound data type: the status of the sensor (string typically containing "nominal") 2028 | hid_t stringTypeStatus = H5Tcopy (H5T_C_S1); 2029 | H5Tset_size(stringTypeStatus, sizeof(cTimestampedDouble::m_chaStatus)); 2030 | H5Tinsert(compoundDataType, "status", HOFFSET(cTimestampedDouble, m_chaStatus), stringTypeStatus); 2031 | 2032 | //Create the data set of of the new compound datatype 2033 | hid_t dataset = H5Dcreate1(m_iH5SensorsDBEGroupHandle, strDatasetName.c_str(), compoundDataType, dataspace, H5P_DEFAULT); 2034 | 2035 | herr_t err = H5Dwrite(dataset, compoundDataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, &m_voROACHADCAttenuationsChan1_dB.front()); 2036 | 2037 | if(err < 0) 2038 | { 2039 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): HDF5 make dataset error" << endl; 2040 | } 2041 | else 2042 | { 2043 | cout << "cSpectrometerHDF5OutputFile::writeLOFrequencies(): Wrote " << m_voROACHADCAttenuationsChan1_dB.size() << " ADC attenuations for chan1." << endl; 2044 | } 2045 | 2046 | addAttributeToDataSet(string("attenuation at input to ADC chan1"), strDatasetName, string("double"), string("dB"), dataset); 2047 | 2048 | H5Tclose(stringTypeStatus); 2049 | H5Tclose(compoundDataType); 2050 | H5Sclose(dataspace); 2051 | H5Dclose(dataset); 2052 | } 2053 | } 2054 | 2055 | float cSpectrometerHDF5OutputFile::calculateFrameAverage(const vector &vi32ChannelData) 2056 | { 2057 | double dAverage = 0.0; 2058 | 2059 | for(uint32_t ui = 0; ui < vi32ChannelData.size(); ui++) 2060 | { 2061 | dAverage += vi32ChannelData[ui]; 2062 | } 2063 | 2064 | dAverage /= (double)vi32ChannelData.size(); 2065 | 2066 | return (float)dAverage; 2067 | } 2068 | 2069 | 2070 | void cSpectrometerHDF5OutputFile::addAttributesToFile(const std::string &strVersion, const std::string &strExperimentID, int64_t i64AugmentTimestamp_us, uint32_t u32AugmentErrors, hid_t fileHandle) 2071 | { 2072 | //Adds the attributes needed for the file as a whole. 2073 | 2074 | hid_t variableLengthStringType; 2075 | variableLengthStringType = H5Tcopy (H5T_C_S1); 2076 | 2077 | H5Tset_size (variableLengthStringType, H5T_VARIABLE); 2078 | 2079 | hid_t attrDataspace = H5Screate(H5S_SCALAR); 2080 | 2081 | hid_t attrVersion = H5Acreate(fileHandle, "version", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2082 | const char* pcVersion = &strVersion[0]; 2083 | H5Awrite(attrVersion, variableLengthStringType, &pcVersion); 2084 | 2085 | hid_t attrExperimentID = H5Acreate(fileHandle, "experiment_id", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2086 | const char* pcExperimentID = &strExperimentID[0]; 2087 | H5Awrite(attrExperimentID, variableLengthStringType, &pcExperimentID); 2088 | 2089 | double dTimestamp_s = (double)i64AugmentTimestamp_us / 1e6; 2090 | hid_t attrAugmentTimestamp = H5Acreate(fileHandle, "augment_ts", H5T_NATIVE_DOUBLE, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2091 | H5Awrite(attrAugmentTimestamp, H5T_NATIVE_DOUBLE, &dTimestamp_s); 2092 | 2093 | hid_t attrAugmentErrors = H5Acreate(fileHandle, "augment_errors", H5T_NATIVE_UINT32, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2094 | H5Awrite(attrAugmentErrors, H5T_NATIVE_UINT32, &u32AugmentErrors); 2095 | 2096 | H5Aclose (attrVersion); 2097 | H5Aclose (attrExperimentID); 2098 | H5Aclose (attrAugmentTimestamp); 2099 | H5Aclose (attrAugmentErrors); 2100 | H5Tclose(variableLengthStringType); 2101 | H5Sclose(attrDataspace); 2102 | } 2103 | 2104 | void cSpectrometerHDF5OutputFile::addAttributeToDataSet(const std::string &strDescription, const std::string &strName, const std::string &strType, const std::string &strUnits, hid_t dataset) 2105 | { 2106 | //Adds the 4 attributes as per KAT7 standard 2107 | 2108 | //Note: dataset must be open before calling this function and will remain open on function return. 2109 | 2110 | //Add attributes for dataset 2111 | hid_t variableLengthStringType; 2112 | variableLengthStringType = H5Tcopy (H5T_C_S1); 2113 | H5Tset_size (variableLengthStringType, H5T_VARIABLE); 2114 | 2115 | hid_t attrDataspace = H5Screate(H5S_SCALAR); 2116 | 2117 | hid_t attrDescription = H5Acreate(dataset, "description", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2118 | const char* pcDescription = &strDescription[0]; 2119 | H5Awrite(attrDescription, variableLengthStringType, &pcDescription); 2120 | 2121 | hid_t attrName = H5Acreate(dataset, "name", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2122 | const char* pcName = &strName[0]; 2123 | H5Awrite(attrName, variableLengthStringType, &pcName); 2124 | 2125 | hid_t attrType = H5Acreate(dataset, "type", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2126 | const char* pcType = &strType[0]; 2127 | H5Awrite(attrType, variableLengthStringType, &pcType); 2128 | 2129 | hid_t attrUnits = H5Acreate(dataset, "units", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2130 | const char* pcUnits = &strUnits[0]; 2131 | H5Awrite(attrUnits, variableLengthStringType, &pcUnits); 2132 | 2133 | H5Aclose (attrDescription); 2134 | H5Aclose (attrName); 2135 | H5Aclose (attrType); 2136 | H5Aclose (attrUnits); 2137 | H5Tclose(variableLengthStringType); 2138 | H5Sclose(attrDataspace); 2139 | } 2140 | 2141 | void cSpectrometerHDF5OutputFile::addAttributesToObservation(const std::string &strScriptName, const std::string &strScriptArguments, const std::string &strObserver, const std::string &strExperimentID, const std::string &strDescription, const std::string &strAntennas, const std::string &strStartTime, const std::string &strEndTime, const std::string &strNoiseDiodeParams, const std::string &strRFParams, const std::string &strStatus, hid_t observationGroup) 2142 | { 2143 | //Adds attributes to the Configuration/Observation group 2144 | 2145 | hid_t variableLengthStringType; 2146 | variableLengthStringType = H5Tcopy (H5T_C_S1); 2147 | 2148 | H5Tset_size (variableLengthStringType, H5T_VARIABLE); 2149 | 2150 | hid_t attrDataspace = H5Screate(H5S_SCALAR); 2151 | 2152 | hid_t attrScriptName = H5Acreate(observationGroup, "script_name", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2153 | const char* pcScriptName = &strScriptName[0]; 2154 | H5Awrite(attrScriptName, variableLengthStringType, &pcScriptName); 2155 | 2156 | hid_t attrScriptArguments = H5Acreate(observationGroup, "script_arguments", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2157 | const char* pcScriptArguments = &strScriptArguments[0]; 2158 | H5Awrite(attrScriptArguments, variableLengthStringType, &pcScriptArguments); 2159 | 2160 | hid_t attrObserver = H5Acreate(observationGroup, "observer", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2161 | const char* pcObserver = &strObserver[0]; 2162 | H5Awrite(attrObserver, variableLengthStringType, &pcObserver); 2163 | 2164 | hid_t attrExperimentID = H5Acreate(observationGroup, "experiment_id", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2165 | const char* pcExperimentID = &strExperimentID[0]; 2166 | H5Awrite(attrExperimentID, variableLengthStringType, &pcExperimentID); 2167 | 2168 | hid_t attrDescription = H5Acreate(observationGroup, "description", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2169 | const char* pcDescription = &strDescription[0]; 2170 | H5Awrite(attrDescription, variableLengthStringType, &pcDescription); 2171 | 2172 | hid_t attrAntennas = H5Acreate(observationGroup, "ants", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2173 | const char* pcAntennas = &strAntennas[0]; 2174 | H5Awrite(attrAntennas, variableLengthStringType, &pcAntennas); 2175 | 2176 | hid_t attrStartTime = H5Acreate(observationGroup, "starttime", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2177 | const char* pcStartTime = &strStartTime[0]; 2178 | H5Awrite(attrStartTime, variableLengthStringType, &pcStartTime); 2179 | 2180 | hid_t attrEndTime = H5Acreate(observationGroup, "endtime", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2181 | const char* pcEndTime = &strEndTime[0]; 2182 | H5Awrite(attrEndTime, variableLengthStringType, &pcEndTime); 2183 | 2184 | hid_t attrNoiseDiodeParams = H5Acreate(observationGroup, "nd_params", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2185 | const char* pcNoiseDiodeParams = &strNoiseDiodeParams[0]; 2186 | H5Awrite(attrNoiseDiodeParams, variableLengthStringType, &pcNoiseDiodeParams); 2187 | 2188 | hid_t attrRFParams = H5Acreate(observationGroup, "rf_params", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2189 | const char* pcRFParams = &strRFParams[0]; 2190 | H5Awrite(attrRFParams, variableLengthStringType, &pcRFParams); 2191 | 2192 | hid_t attrStatus = H5Acreate(observationGroup, "status", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2193 | const char* pcStatus = &strStatus[0]; 2194 | H5Awrite(attrStatus, variableLengthStringType, &pcStatus); 2195 | 2196 | H5Aclose(attrScriptName); 2197 | H5Aclose(attrScriptArguments); 2198 | H5Aclose(attrObserver); 2199 | H5Aclose(attrExperimentID); 2200 | H5Aclose(attrDescription); 2201 | H5Aclose(attrAntennas); 2202 | H5Aclose(attrStartTime); 2203 | H5Aclose(attrEndTime); 2204 | H5Aclose(attrNoiseDiodeParams); 2205 | H5Aclose(attrRFParams); 2206 | H5Aclose(attrStatus); 2207 | H5Tclose(variableLengthStringType); 2208 | H5Sclose(attrDataspace); 2209 | } 2210 | 2211 | void cSpectrometerHDF5OutputFile::addAttributesToDBE(const std::string &strVisOrdering, const std::string &strStokesOrdering, hid_t DBEGroup) 2212 | { 2213 | hid_t variableLengthStringType; 2214 | variableLengthStringType = H5Tcopy (H5T_C_S1); 2215 | 2216 | H5Tset_size (variableLengthStringType, H5T_VARIABLE); 2217 | 2218 | hid_t attrDataspace = H5Screate(H5S_SCALAR); 2219 | 2220 | hid_t attrVisOrdering = H5Acreate(DBEGroup, "vis_ordering", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2221 | const char* pcVisOrdering = &strVisOrdering[0]; 2222 | H5Awrite(attrVisOrdering, variableLengthStringType, &pcVisOrdering); 2223 | 2224 | hid_t attrStokesOrdering = H5Acreate(DBEGroup, "stokes_ordering", variableLengthStringType, attrDataspace, H5P_DEFAULT, H5P_DEFAULT); 2225 | const char* pcStokesOrdering = &strStokesOrdering[0]; 2226 | H5Awrite(attrStokesOrdering, variableLengthStringType, &pcStokesOrdering); 2227 | 2228 | H5Aclose(attrVisOrdering); 2229 | H5Aclose(attrStokesOrdering); 2230 | H5Tclose(variableLengthStringType); 2231 | H5Sclose(attrDataspace); 2232 | } 2233 | 2234 | //Functions for adding logged data from outside this class 2235 | //Each function aquires a shared lock of a common shared mutex for adding data to its respective vector. 2236 | //When all of this data is written to file a unique lock is obtained from that mutex so that none of the data be altered at that point 2237 | void cSpectrometerHDF5OutputFile::addMarkupLabel(int64_t i64Timestamp_us, const string &strLabel) 2238 | { 2239 | cMarkupLabels oNewMarkupLabel; 2240 | oNewMarkupLabel.m_dTimestamp_s = double(i64Timestamp_us) / 1e6; 2241 | sprintf(oNewMarkupLabel.m_chaLabel, strLabel.c_str()); 2242 | 2243 | boost::shared_lock oLock(m_oAppendDataMutex); 2244 | 2245 | m_voMarkupLabels.push_back(oNewMarkupLabel); 2246 | } 2247 | 2248 | void cSpectrometerHDF5OutputFile::addRequestedAntennaAz(int64_t i64Timestamp_us, double dAzimuth_deg, const string &strStatus) 2249 | { 2250 | cTimestampedDouble oNewRequestedAntennaAz; 2251 | oNewRequestedAntennaAz.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2252 | oNewRequestedAntennaAz.m_dValue = dAzimuth_deg; 2253 | sprintf(oNewRequestedAntennaAz.m_chaStatus, strStatus.c_str()); 2254 | 2255 | boost::shared_lock oLock(m_oAppendDataMutex); 2256 | 2257 | m_voRequestedAntennaAzs_deg.push_back(oNewRequestedAntennaAz); 2258 | } 2259 | 2260 | void cSpectrometerHDF5OutputFile::addRequestedAntennaEl(int64_t i64Timestamp_us, double dElevation_deg, const string &strStatus) 2261 | { 2262 | cTimestampedDouble oNewRequestedAntennaEl; 2263 | oNewRequestedAntennaEl.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2264 | oNewRequestedAntennaEl.m_dValue = dElevation_deg; 2265 | sprintf(oNewRequestedAntennaEl.m_chaStatus, strStatus.c_str()); 2266 | 2267 | boost::shared_lock oLock(m_oAppendDataMutex); 2268 | 2269 | m_voRequestedAntennaEls_deg.push_back(oNewRequestedAntennaEl); 2270 | } 2271 | 2272 | void cSpectrometerHDF5OutputFile::addActualAntennaAz(int64_t i64Timestamp_us, double dAzimuth_deg, const string &strStatus) 2273 | { 2274 | cTimestampedDouble oNewActualAntennaAz; 2275 | oNewActualAntennaAz.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2276 | oNewActualAntennaAz.m_dValue = dAzimuth_deg; 2277 | sprintf(oNewActualAntennaAz.m_chaStatus, strStatus.c_str()); 2278 | 2279 | boost::shared_lock oLock(m_oAppendDataMutex); 2280 | 2281 | m_voActualAntennaAzs_deg.push_back(oNewActualAntennaAz); 2282 | } 2283 | 2284 | void cSpectrometerHDF5OutputFile::addActualAntennaEl(int64_t i64Timestamp_us, double dElevation_deg, const string &strStatus) 2285 | { 2286 | cTimestampedDouble oNewActualAntennaEl; 2287 | oNewActualAntennaEl.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2288 | oNewActualAntennaEl.m_dValue = dElevation_deg; 2289 | sprintf(oNewActualAntennaEl.m_chaStatus, strStatus.c_str()); 2290 | 2291 | boost::shared_lock oLock(m_oAppendDataMutex); 2292 | 2293 | m_voActualAntennaEls_deg.push_back(oNewActualAntennaEl); 2294 | } 2295 | 2296 | void cSpectrometerHDF5OutputFile::addActualSourceOffsetAz(int64_t i64Timestamp_us, double dAzimuthOffset_deg, const string &strStatus) 2297 | { 2298 | cTimestampedDouble oNewActualSourceOffsetAz; 2299 | oNewActualSourceOffsetAz.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2300 | oNewActualSourceOffsetAz.m_dValue = dAzimuthOffset_deg; 2301 | sprintf(oNewActualSourceOffsetAz.m_chaStatus, strStatus.c_str()); 2302 | 2303 | boost::shared_lock oLock(m_oAppendDataMutex); 2304 | 2305 | m_voActualSourceOffsetAzs_deg.push_back(oNewActualSourceOffsetAz); 2306 | } 2307 | 2308 | void cSpectrometerHDF5OutputFile::addActualSourceOffsetEl(int64_t i64Timestamp_us, double dElevationOffset_deg, const string &strStatus) 2309 | { 2310 | cTimestampedDouble oNewActualSourceOffsetEl; 2311 | oNewActualSourceOffsetEl.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2312 | oNewActualSourceOffsetEl.m_dValue = dElevationOffset_deg; 2313 | sprintf(oNewActualSourceOffsetEl.m_chaStatus, strStatus.c_str()); 2314 | 2315 | boost::shared_lock oLock(m_oAppendDataMutex); 2316 | 2317 | m_voActualSourceOffsetEls_deg.push_back(oNewActualSourceOffsetEl); 2318 | } 2319 | 2320 | void cSpectrometerHDF5OutputFile::addActualAntennaRA(int64_t i64Timestamp_us, double dRighAscension_deg, const string &strStatus) 2321 | { 2322 | cTimestampedDouble oNewActualAntennaRA; 2323 | oNewActualAntennaRA.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2324 | oNewActualAntennaRA.m_dValue = dRighAscension_deg; 2325 | sprintf(oNewActualAntennaRA.m_chaStatus, strStatus.c_str()); 2326 | 2327 | boost::shared_lock oLock(m_oAppendDataMutex); 2328 | 2329 | m_voActualAntennaRAs_deg.push_back(oNewActualAntennaRA); 2330 | } 2331 | 2332 | void cSpectrometerHDF5OutputFile::addActualAntennaDec(int64_t i64Timestamp_us, double dDeclination_deg, const string &strStatus) 2333 | { 2334 | cTimestampedDouble oNewActualAntennaDec; 2335 | oNewActualAntennaDec.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2336 | oNewActualAntennaDec.m_dValue = dDeclination_deg; 2337 | sprintf(oNewActualAntennaDec.m_chaStatus, strStatus.c_str()); 2338 | 2339 | boost::shared_lock oLock(m_oAppendDataMutex); 2340 | 2341 | m_voActualAntennaDecs_deg.push_back(oNewActualAntennaDec); 2342 | } 2343 | 2344 | void cSpectrometerHDF5OutputFile::addAntennaStatus(int64_t i64Timestamp_us, const string &strAntennaStatus, const string &strStatus) 2345 | { 2346 | boost::shared_lock oLock(m_oAppendDataMutex); 2347 | 2348 | cAntennaStatus oNewAntennaStatus; 2349 | oNewAntennaStatus.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2350 | sprintf( oNewAntennaStatus.m_chaAntennaStatus, strAntennaStatus.substr(0, sizeof(oNewAntennaStatus.m_chaAntennaStatus)).c_str() ); //Limit to size of the char array 2351 | sprintf( oNewAntennaStatus.m_chaStatus, strStatus.c_str()); 2352 | 2353 | //The numerical value is not used here 2354 | 2355 | m_voAntennaStatuses.push_back(oNewAntennaStatus); 2356 | } 2357 | 2358 | void cSpectrometerHDF5OutputFile::motorTorqueAzMaster(int64_t i64Timestamp_us, double dAzMaster_mNm, const string &strStatus) 2359 | { 2360 | cTimestampedDouble oNewMotorTorque; 2361 | oNewMotorTorque.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2362 | oNewMotorTorque.m_dValue = dAzMaster_mNm; 2363 | sprintf(oNewMotorTorque.m_chaStatus, strStatus.c_str()); 2364 | 2365 | boost::shared_lock oLock(m_oAppendDataMutex); 2366 | 2367 | m_voMotorTorquesAzMaster_mNm.push_back(oNewMotorTorque); 2368 | } 2369 | 2370 | void cSpectrometerHDF5OutputFile::motorTorqueAzSlave(int64_t i64Timestamp_us, double dAzSlave_mNm, const string &strStatus) 2371 | { 2372 | cTimestampedDouble oNewMotorTorque; 2373 | oNewMotorTorque.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2374 | oNewMotorTorque.m_dValue = dAzSlave_mNm; 2375 | sprintf(oNewMotorTorque.m_chaStatus, strStatus.c_str()); 2376 | 2377 | boost::shared_lock oLock(m_oAppendDataMutex); 2378 | 2379 | m_voMotorTorquesAzSlave_mNm.push_back(oNewMotorTorque); 2380 | } 2381 | 2382 | void cSpectrometerHDF5OutputFile::motorTorqueElMaster(int64_t i64Timestamp_us, double dElMaster_mNm, const string &strStatus) 2383 | { 2384 | cTimestampedDouble oNewMotorTorque; 2385 | oNewMotorTorque.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2386 | oNewMotorTorque.m_dValue = dElMaster_mNm; 2387 | sprintf(oNewMotorTorque.m_chaStatus, strStatus.c_str()); 2388 | 2389 | boost::shared_lock oLock(m_oAppendDataMutex); 2390 | 2391 | m_voMotorTorquesElMaster_mNm.push_back(oNewMotorTorque); 2392 | } 2393 | 2394 | void cSpectrometerHDF5OutputFile::motorTorqueElSlave(int64_t i64Timestamp_us, double dElSlave_mNm, const string &strStatus) 2395 | { 2396 | cTimestampedDouble oNewMotorTorque; 2397 | oNewMotorTorque.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2398 | oNewMotorTorque.m_dValue = dElSlave_mNm; 2399 | sprintf(oNewMotorTorque.m_chaStatus, strStatus.c_str()); 2400 | 2401 | boost::shared_lock oLock(m_oAppendDataMutex); 2402 | 2403 | m_voMotorTorquesElSlave_mNm.push_back(oNewMotorTorque); 2404 | } 2405 | 2406 | void cSpectrometerHDF5OutputFile::setAppliedPointingModel(const string &strModelName, const vector &vdPointingModelParams) 2407 | { 2408 | boost::shared_lock oLock(m_oAppendDataMutex); 2409 | 2410 | //This only a single set of values, not a history of values. 2411 | //Update the current record whenever a new value is received 2412 | 2413 | m_vdPointingModelParams = vdPointingModelParams; 2414 | sprintf(m_oAntennaConfiguration.m_chaPointModelName, strModelName.c_str()); 2415 | } 2416 | 2417 | void cSpectrometerHDF5OutputFile::setAntennaName(const string &strAntennaName) 2418 | { 2419 | boost::shared_lock oLock(m_oAppendDataMutex); 2420 | //Only a single set of values 2421 | sprintf(m_oAntennaConfiguration.m_chaAntennaName, strAntennaName.c_str()); 2422 | } 2423 | 2424 | void cSpectrometerHDF5OutputFile::setAntennaDiameter(const string &strAntennaDiameter_m) 2425 | { 2426 | boost::shared_lock oLock(m_oAppendDataMutex); 2427 | //Only a single set of values 2428 | sprintf(m_oAntennaConfiguration.m_chaAntennaDiameter_m, strAntennaDiameter_m.c_str()); 2429 | } 2430 | 2431 | void cSpectrometerHDF5OutputFile::setAntennaBeamwidth(const string &strAntennaBeamwidth_deg) 2432 | { 2433 | boost::shared_lock oLock(m_oAppendDataMutex); 2434 | //Only a single set of values 2435 | sprintf(m_oAntennaConfiguration.m_chaAntennaBeamwidth, strAntennaBeamwidth_deg.c_str()); 2436 | } 2437 | 2438 | void cSpectrometerHDF5OutputFile::setAntennaLongitude(const string &strAntennaLongitude_deg) 2439 | { 2440 | boost::shared_lock oLock(m_oAppendDataMutex); 2441 | //Only a single set of values 2442 | sprintf(m_oAntennaConfiguration.m_chaAntennaLongitude_deg, strAntennaLongitude_deg.c_str()); 2443 | } 2444 | 2445 | void cSpectrometerHDF5OutputFile::setAntennaLatitude(const string &strAntennaLatitude_deg) 2446 | { 2447 | boost::shared_lock oLock(m_oAppendDataMutex); 2448 | //Only a single set of values 2449 | sprintf(m_oAntennaConfiguration.m_chaAntennaLatitude_deg, strAntennaLatitude_deg.c_str()); 2450 | } 2451 | 2452 | void cSpectrometerHDF5OutputFile::setAntennaAltitude(const string &strAntennAltitude_m) 2453 | { 2454 | boost::shared_lock oLock(m_oAppendDataMutex); 2455 | //Only a single set of values 2456 | sprintf(m_oAntennaConfiguration.m_chaAntennaAltitude_m, strAntennAltitude_m.c_str()); 2457 | } 2458 | 2459 | void cSpectrometerHDF5OutputFile::setAntennaDelayModel(const vector &vdDelayModelParams) 2460 | { 2461 | boost::shared_lock oLock(m_oAppendDataMutex); 2462 | //This only a single set of values, not a history of values. 2463 | //Update the current record whenever a new value is received 2464 | 2465 | m_vdDelayModelParams = vdDelayModelParams; 2466 | } 2467 | 2468 | void cSpectrometerHDF5OutputFile::addNoiseDiodeSoftwareState(int64_t i64Timestamp_us, int32_t i32NoiseDiodeState, const string &strStatus) 2469 | { 2470 | boost::shared_lock oLock(m_oAppendDataMutex); 2471 | 2472 | cTimestampedInt oNewNoiseDiodeState; 2473 | oNewNoiseDiodeState.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2474 | oNewNoiseDiodeState.m_i32Value = i32NoiseDiodeState; 2475 | sprintf(oNewNoiseDiodeState.m_chaStatus, strStatus.c_str()); 2476 | 2477 | m_voNoiseDiodeSoftwareStates.push_back(oNewNoiseDiodeState); 2478 | } 2479 | 2480 | void cSpectrometerHDF5OutputFile::addNoiseDiodeSource(int64_t i64Timestamp_us, const string &strNoiseSource, const string &strStatus) 2481 | { 2482 | boost::shared_lock oLock(m_oAppendDataMutex); 2483 | 2484 | cNoiseDiodeSource oNewNoiseDiodeSource; 2485 | oNewNoiseDiodeSource.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2486 | sprintf( oNewNoiseDiodeSource.m_chaSource, strNoiseSource.substr(0, sizeof(oNewNoiseDiodeSource.m_chaSource)).c_str() ); //Limit to size of the char array 2487 | sprintf( oNewNoiseDiodeSource.m_chaStatus, strStatus.c_str()); 2488 | 2489 | m_voNoiseDiodeSources.push_back(oNewNoiseDiodeSource); 2490 | } 2491 | 2492 | void cSpectrometerHDF5OutputFile::addNoiseDiodeCurrent(int64_t i64Timestamp_us, double dNoiseDiodeCurrent_A, const string &strStatus) 2493 | { 2494 | boost::shared_lock oLock(m_oAppendDataMutex); 2495 | 2496 | cTimestampedDouble oNewNoiseDiodeCurrent; 2497 | oNewNoiseDiodeCurrent.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2498 | oNewNoiseDiodeCurrent.m_dValue = dNoiseDiodeCurrent_A; 2499 | sprintf(oNewNoiseDiodeCurrent.m_chaStatus, strStatus.c_str()); 2500 | 2501 | 2502 | m_voNoiseDiodeCurrents.push_back(oNewNoiseDiodeCurrent); 2503 | } 2504 | 2505 | void cSpectrometerHDF5OutputFile::addSourceSelection(int64_t i64Timestamp_us, const string &strSourceName, double dRighAscension_deg, double dDeclination_deg) 2506 | { 2507 | boost::shared_lock oLock(m_oAppendDataMutex); 2508 | 2509 | //Construct as per KAT7 standard 2510 | //Source name if available, RA and Dec in DMS 2511 | 2512 | int32_t i32RA_deg; 2513 | int32_t i32RA_min; 2514 | double dRA_s; 2515 | AVN::cCoordinatePosition::decimalDegreesToDMS(dRighAscension_deg, i32RA_deg, i32RA_min, dRA_s); 2516 | 2517 | int32_t i32Dec_deg; 2518 | int32_t i32Dec_min; 2519 | double dDec_s; 2520 | AVN::cCoordinatePosition::decimalDegreesToDMS(dDeclination_deg, i32Dec_deg, i32Dec_min, dDec_s); 2521 | 2522 | stringstream oSS; 2523 | if(strSourceName.length()) 2524 | { 2525 | oSS << strSourceName; 2526 | oSS << ", "; 2527 | } 2528 | 2529 | oSS << "radec, "; 2530 | oSS << i32RA_deg << ":" << i32RA_min << ":" << dRA_s << ", "; 2531 | oSS << i32Dec_deg << ":" << i32Dec_min << ":" << dDec_s; 2532 | 2533 | cSourceSelection oNewSourceSelection; 2534 | 2535 | oNewSourceSelection.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2536 | sprintf(oNewSourceSelection.m_chaSource, oSS.str().substr(0, sizeof(oNewSourceSelection.m_chaSource)).c_str() ); //Limit to size of the char array 2537 | sprintf(oNewSourceSelection.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. Adapt with available status data. 2538 | 2539 | m_voSelectedSources.push_back(oNewSourceSelection); 2540 | } 2541 | 2542 | //FOOBAR 2543 | void cSpectrometerHDF5OutputFile::addFrequencySelectLCP(int64_t i64Timestamp_us, bool bFrequencySelectLCP, const string &strStatus) 2544 | { 2545 | boost::shared_lock oLock(m_oAppendDataMutex); 2546 | 2547 | cTimestampedChar oNewFrequencyLCP; 2548 | oNewFrequencyLCP.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2549 | //oNewFrequencyLCP.m_chaValue = bFreqencySelectLCP; 2550 | sprintf(oNewFrequencyLCP.m_chaValue, "%s", (bFrequencySelectLCP)?"1":"0"); 2551 | sprintf(oNewFrequencyLCP.m_chaStatus, strStatus.c_str()); 2552 | 2553 | m_voFrequencySelectLCP.push_back(oNewFrequencyLCP); 2554 | } 2555 | 2556 | void cSpectrometerHDF5OutputFile::addFrequencySelectRCP(int64_t i64Timestamp_us, bool bFrequencySelectRCP, const string &strStatus) 2557 | { 2558 | boost::shared_lock oLock(m_oAppendDataMutex); 2559 | 2560 | cTimestampedChar oNewRFFrequency; 2561 | oNewRFFrequency.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2562 | //oNewRFFrequency.m_chaValue = bFrequencySelectRCP; 2563 | sprintf(oNewRFFrequency.m_chaValue, "%s", (bFrequencySelectRCP)?"1":"0"); 2564 | sprintf(oNewRFFrequency.m_chaStatus, strStatus.c_str()); 2565 | 2566 | m_voFrequencySelectRCP.push_back(oNewRFFrequency); 2567 | } 2568 | 2569 | void cSpectrometerHDF5OutputFile::addFrequencyLO0Chan0(int64_t i64Timestamp_us, double dFrequencyLO0Chan0_Hz, const string &strStatus) 2570 | { 2571 | cTimestampedDouble oNewLOFrequency; 2572 | oNewLOFrequency.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2573 | oNewLOFrequency.m_dValue = dFrequencyLO0Chan0_Hz; 2574 | sprintf(oNewLOFrequency.m_chaStatus, strStatus.c_str()); 2575 | 2576 | boost::shared_lock oLock(m_oAppendDataMutex); 2577 | 2578 | m_voFrequenciesLO0Chan0_Hz.push_back(oNewLOFrequency); 2579 | } 2580 | 2581 | void cSpectrometerHDF5OutputFile::addFrequencyLO0Chan1(int64_t i64Timestamp_us, double dFrequencyLO0Chan1_Hz, const string &strStatus) 2582 | { 2583 | cTimestampedDouble oNewLOFrequency; 2584 | oNewLOFrequency.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2585 | oNewLOFrequency.m_dValue = dFrequencyLO0Chan1_Hz; 2586 | sprintf(oNewLOFrequency.m_chaStatus, strStatus.c_str()); 2587 | 2588 | boost::shared_lock oLock(m_oAppendDataMutex); 2589 | 2590 | m_voFrequenciesLO0Chan1_Hz.push_back(oNewLOFrequency); 2591 | } 2592 | 2593 | void cSpectrometerHDF5OutputFile::addFrequencyLO1(int64_t i64Timestamp_us, double dFrequencyLO1_Hz, const string &strStatus) 2594 | { 2595 | cTimestampedDouble oNewLOFrequency; 2596 | oNewLOFrequency.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2597 | oNewLOFrequency.m_dValue = dFrequencyLO1_Hz; 2598 | sprintf(oNewLOFrequency.m_chaStatus, strStatus.c_str()); 2599 | 2600 | boost::shared_lock oLock(m_oAppendDataMutex); 2601 | 2602 | m_voFrequenciesLO1_Hz.push_back(oNewLOFrequency); 2603 | } 2604 | 2605 | void cSpectrometerHDF5OutputFile::addReceiverBandwidthChan0(int64_t i64Timestamp_us, double dReceiverBandwidthChan0_Hz, const string &strStatus) 2606 | { 2607 | boost::shared_lock oLock(m_oAppendDataMutex); 2608 | 2609 | cTimestampedDouble oNewBandwidthIF; 2610 | oNewBandwidthIF.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2611 | oNewBandwidthIF.m_dValue = dReceiverBandwidthChan0_Hz; 2612 | sprintf(oNewBandwidthIF.m_chaStatus, strStatus.c_str()); 2613 | 2614 | m_voReceiverBandwidthsChan0_Hz.push_back(oNewBandwidthIF); 2615 | } 2616 | 2617 | void cSpectrometerHDF5OutputFile::addReceiverBandwidthChan1(int64_t i64Timestamp_us, double dReceiverBandwidthChan1_Hz, const string &strStatus) 2618 | { 2619 | boost::shared_lock oLock(m_oAppendDataMutex); 2620 | 2621 | cTimestampedDouble oNewBandwidthIF; 2622 | oNewBandwidthIF.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2623 | oNewBandwidthIF.m_dValue = dReceiverBandwidthChan1_Hz; 2624 | sprintf(oNewBandwidthIF.m_chaStatus, strStatus.c_str()); 2625 | 2626 | m_voReceiverBandwidthsChan1_Hz.push_back(oNewBandwidthIF); 2627 | } 2628 | 2629 | void cSpectrometerHDF5OutputFile::addAccumulationLength(int64_t i64Timestamp_us, uint32_t u32NFrames) 2630 | { 2631 | boost::shared_lock oLock(m_oAppendDataMutex); 2632 | 2633 | cTimestampedUnsignedInt oNewAccumulationLength; 2634 | oNewAccumulationLength.m_dTimestamp_s = (double)i64Timestamp_us / 1e6; 2635 | oNewAccumulationLength.m_u32Value = u32NFrames; 2636 | sprintf(oNewAccumulationLength.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. Adapt with available status data. 2637 | 2638 | m_voROACHAccumulationLengths_nFrames.push_back(oNewAccumulationLength); 2639 | } 2640 | 2641 | void cSpectrometerHDF5OutputFile::addCoarseChannelSelect(int64_t i64Timestamp_us, uint32_t u32ChannelNo) 2642 | { 2643 | boost::shared_lock oLock(m_oAppendDataMutex); 2644 | 2645 | if (!m_voROACHNBChannelSelects.size() || u32ChannelNo != m_voROACHNBChannelSelects[m_voROACHNBChannelSelects.size() - 1].m_u32Value) 2646 | { 2647 | cTimestampedUnsignedInt oNewCoarseChannelSelection; 2648 | oNewCoarseChannelSelection.m_dTimestamp_s = i64Timestamp_us / 1e6; //Convert from us to standard s 2649 | oNewCoarseChannelSelection.m_u32Value = u32ChannelNo; 2650 | sprintf(oNewCoarseChannelSelection.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. Adapt with available status data. 2651 | 2652 | m_voROACHNBChannelSelects.push_back(oNewCoarseChannelSelection); 2653 | } 2654 | } 2655 | 2656 | void cSpectrometerHDF5OutputFile::setFrequencyFs(double dFrequencyFs_Hz) 2657 | { 2658 | boost::shared_lock oLock(m_oAppendDataMutex); 2659 | 2660 | //This only a single value, not a history of values. 2661 | //Update the current record whenever a new value is received 2662 | 2663 | m_dROACHFrequencyFs_Hz = dFrequencyFs_Hz; 2664 | } 2665 | 2666 | void cSpectrometerHDF5OutputFile::setSizeOfCoarseFFT(uint32_t u32SizeOfCoarseFFT_nSamp) 2667 | { 2668 | boost::shared_lock oLock(m_oAppendDataMutex); 2669 | 2670 | m_u32ROACHSizeOfCoarseFFT_nSamp = u32SizeOfCoarseFFT_nSamp; 2671 | //cout << "cSpectrometerHDF5OutputFile::setSizeOfCoarseFFT(): wrote size of coarse FFT " << u32SizeOfCoarseFFT_nSamp << endl; 2672 | } 2673 | 2674 | void cSpectrometerHDF5OutputFile::setSizeOfFineFFT(uint32_t u32SizeOfFineFFT_nSamp) 2675 | { 2676 | boost::shared_lock oLock(m_oAppendDataMutex); 2677 | 2678 | m_u32ROACHSizeOfFineFFT_nSamp = u32SizeOfFineFFT_nSamp; 2679 | //cout << "cSpectrometerHDF5OutputFile::setSizeOfFineFFT(): wrote size of fine FFT " << u32SizeOfFineFFT_nSamp << endl; 2680 | } 2681 | 2682 | void cSpectrometerHDF5OutputFile::addCoarseFFTShiftMask(int64_t i64Timestamp_us, uint32_t u32ShiftMask) 2683 | { 2684 | if (!m_voROACHCoarseFFTShiftMasks.size() || u32ShiftMask != m_voROACHCoarseFFTShiftMasks[m_voROACHCoarseFFTShiftMasks.size() - 1].m_u32Value) 2685 | { 2686 | cTimestampedUnsignedInt oNewCoarseFFTShift; 2687 | oNewCoarseFFTShift.m_dTimestamp_s = i64Timestamp_us / 1e6; 2688 | oNewCoarseFFTShift.m_u32Value = u32ShiftMask; 2689 | sprintf(oNewCoarseFFTShift.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. Adapt with available status data. 2690 | 2691 | boost::shared_lock oLock(m_oAppendDataMutex); 2692 | 2693 | m_voROACHCoarseFFTShiftMasks.push_back(oNewCoarseFFTShift); 2694 | } 2695 | } 2696 | 2697 | void cSpectrometerHDF5OutputFile::addAttenuationADCChan0(int64_t i64Timestamp_us, double dADCAttenuationChan0_dB) 2698 | { 2699 | if (!m_voROACHADCAttenuationsChan0_dB.size() || dADCAttenuationChan0_dB != m_voROACHADCAttenuationsChan0_dB[m_voROACHADCAttenuationsChan0_dB.size() - 1].m_dValue) 2700 | { 2701 | cTimestampedDouble oNewAdcAttenuantion; 2702 | oNewAdcAttenuantion.m_dTimestamp_s = i64Timestamp_us / 1e6; 2703 | oNewAdcAttenuantion.m_dValue = dADCAttenuationChan0_dB; 2704 | sprintf(oNewAdcAttenuantion.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. Adapt with available status data. 2705 | 2706 | boost::shared_lock oLock(m_oAppendDataMutex); 2707 | 2708 | m_voROACHADCAttenuationsChan0_dB.push_back(oNewAdcAttenuantion); 2709 | } 2710 | } 2711 | 2712 | void cSpectrometerHDF5OutputFile::addAttenuationADCChan1(int64_t i64Timestamp_us, double dADCAttenuationChan1_dB) 2713 | { 2714 | if (!m_voROACHADCAttenuationsChan1_dB.size() || dADCAttenuationChan1_dB != m_voROACHADCAttenuationsChan1_dB[m_voROACHADCAttenuationsChan1_dB.size() - 1].m_dValue) 2715 | { 2716 | cTimestampedDouble oNewAdcAttenuantion; 2717 | oNewAdcAttenuantion.m_dTimestamp_s = i64Timestamp_us / 1e6; 2718 | oNewAdcAttenuantion.m_dValue = dADCAttenuationChan1_dB; 2719 | sprintf(oNewAdcAttenuantion.m_chaStatus, "nominal"); //This is hardcoded to always be nominal for now for compatability with KATDal. Adapt with available status data. 2720 | 2721 | boost::shared_lock oLock(m_oAppendDataMutex); 2722 | 2723 | m_voROACHADCAttenuationsChan1_dB.push_back(oNewAdcAttenuantion); 2724 | } 2725 | } 2726 | --------------------------------------------------------------------------------