/*************************************************************************** * Copyright (C) 2009 by gempa GmbH * * * * All Rights Reserved. * * * * NOTICE: All information contained herein is, and remains * * the property of gempa GmbH and its suppliers, if any. The intellectual * * and technical concepts contained herein are proprietary to gempa GmbH * * and its suppliers. * * Dissemination of this information or reproduction of this material * * is strictly forbidden unless prior written permission is obtained * * from gempa GmbH. * ***************************************************************************/ #ifndef GEMPA_CAPS_PACKET_H #define GEMPA_CAPS_PACKET_H #include #include #include #include #include #include #include namespace Gempa { namespace CAPS { enum PacketType { UnknownPacket = 0, RawDataPacket, MSEEDPacket, ANYPacket, RTCM2Packet, MetaDataPacket, FixedRawDataPacket, PacketTypeCount }; enum DataType { DT_Unknown = 0, DT_DOUBLE = 1, DT_FLOAT = 2, DT_INT64 = 100, DT_INT32 = 101, DT_INT16 = 102, DT_INT8 = 103 }; union UOM { char str[4]; int32_t ID; }; union Quality { char str[4]; int32_t ID; }; struct SC_GEMPA_CAPS_API TimeStamp { int16_t year; /* year, eg. 2003 */ uint16_t yday; /* day of year (1-366) */ uint8_t hour; /* hour (0-23) */ uint8_t minute; /* minute (0-59) */ uint8_t second; /* second (0-59), 60 if leap second */ uint8_t unused; /* unused byte */ int32_t usec; /* microsecond (0-999999) */ }; struct SC_GEMPA_CAPS_API PacketDataHeader { PacketDataHeader() : version(1), packetType(UnknownPacket) { unitOfMeasurement.ID = 0; } PacketDataHeader(uint16_t version) : version(version) , packetType(UnknownPacket) { unitOfMeasurement.ID = 0; } uint16_t version; PacketType packetType; UOM unitOfMeasurement; bool setUOM(const char *type); std::string uom(char fill = '\0') const; bool operator!=(const PacketDataHeader &other) const; int dataSize() const { return sizeof(version) + sizeof((char)packetType) + sizeof(unitOfMeasurement.ID); } bool put(std::streambuf &buf) const { Endianess::Writer put(buf); char type = char(packetType); put(version); put(type); put(unitOfMeasurement.ID); return put.good; } bool get(std::streambuf &buf) { Endianess::Reader get(buf); char type; get(version); get(type); packetType = PacketType(type); get(unitOfMeasurement.ID); return get.good; } }; struct SC_GEMPA_CAPS_API PacketDataHeaderV2 : PacketDataHeader { PacketDataHeaderV2() : PacketDataHeader(2) , samplingFrequencyNumerator(0) , samplingFrequencyDenominator(0) {} uint16_t samplingFrequencyNumerator; uint16_t samplingFrequencyDenominator; Quality quality; bool operator!=(const PacketDataHeaderV2 &other) const; int dataSize() const { return PacketDataHeader::dataSize() + sizeof(samplingFrequencyNumerator) + sizeof(samplingFrequencyDenominator) + sizeof(quality); } bool put(std::streambuf &buf) const { Endianess::Writer put(buf); PacketDataHeader::put(buf); put(samplingFrequencyNumerator); put(samplingFrequencyDenominator); put(quality); return put.good; } bool get(std::streambuf &buf) { Endianess::Reader get(buf); PacketDataHeader::get(buf); get(samplingFrequencyNumerator); get(samplingFrequencyDenominator); get(quality); return get.good; } }; enum StreamIDComponent { NetworkCode = 0, StationCode = 1, LocationCode = 2, ChannelCode = 3, StreamIDComponentSize }; struct SC_GEMPA_CAPS_API PacketHeaderV1 { uint8_t SIDSize[4]; /* number of bytes of stream ID components */ uint16_t size; /* number of data bytes */ bool put(std::streambuf &buf) { Endianess::Writer put(buf); for ( int i = 0; i < 4; ++i ) put(SIDSize[i]); put(size); return put.good; } size_t dataSize() const { return sizeof(uint8_t) * 4 + sizeof(size); } }; struct SC_GEMPA_CAPS_API PacketHeaderV2 { uint8_t SIDSize[4]; /* number of bytes of stream ID components */ uint32_t size; /* number of data bytes */ bool put(std::streambuf &buf) { Endianess::Writer put(buf); for ( int i = 0; i < 4; ++i ) put(SIDSize[i]); put(size); return put.good; } size_t dataSize() const { return sizeof(uint8_t) * 4 + sizeof(size); } }; struct SC_GEMPA_CAPS_API ResponseHeader { uint16_t id; int32_t size; bool get(std::streambuf &buf) { Endianess::Reader get(buf); get(id); get(size); return get.good; } }; class SC_GEMPA_CAPS_API DataRecord { public: typedef std::vector Buffer; struct Header { DataType dataType{DT_Unknown}; TimeStamp samplingTime; uint16_t samplingFrequencyNumerator; uint16_t samplingFrequencyDenominator; Quality quality{}; Header() = default; bool get(std::streambuf &buf) { Endianess::Reader get(buf); char dt; get(dt); dataType = (DataType)dt; quality.ID = 0; // Quality is not yet part of the header stream get(samplingTime.year); get(samplingTime.yday); get(samplingTime.hour); get(samplingTime.minute); get(samplingTime.second); get(samplingTime.usec); get(samplingFrequencyNumerator); get(samplingFrequencyDenominator); return get.good; } bool put(std::streambuf &buf) const; int dataSize() const { return sizeof(samplingTime.year) + sizeof(samplingTime.yday) + sizeof(samplingTime.hour) + sizeof(samplingTime.minute) + sizeof(samplingTime.second) + sizeof(samplingTime.usec) + sizeof(samplingFrequencyNumerator) + sizeof(samplingFrequencyDenominator) + sizeof(char); } bool compatible(const Header &other) const; bool operator!=(const Header &other) const; void setSamplingTime(const Time ×tamp); }; enum ReadStatusCode { RS_Error = 0, RS_Complete = 1, RS_Partial = 2, RS_BeforeTimeWindow = 3, RS_AfterTimeWindow = 4, RS_Max }; class ReadStatus { public: ReadStatus() {} ReadStatus(ReadStatusCode code) : _code(code) {} ReadStatus(const ReadStatus &other) : _code(other._code) {} public: ReadStatus &operator=(const ReadStatus &other) { _code = other._code; return *this; } operator ReadStatusCode() const { return _code; } private: operator bool() { return _code != RS_Error; } private: ReadStatusCode _code; }; public: virtual ~DataRecord(); virtual const char *formatName() const = 0; virtual bool readMetaData(std::streambuf &buf, int size, Header &header, Time &startTime, Time &endTime) = 0; //! Returns if data trimming is supported virtual bool canTrim() const = 0; //! Returns if data merging is possible without modifying //! preceding data virtual bool canMerge() const = 0; //! Trims a record to start and end time. Trimming //! should not modify any data but give access to trimmed //! start and end times and the resulting data size. The trimming //! also influences writing the record to a stream. //! Trimming requires the resulting start time being greater //! or equal than the requested start time. //! (Un)Trimming to the original record is semantically //! equal to passing an invalid start and end time. //! It returns true if trimming has been done or false //! if an error occured or trimming is not supported. virtual bool trim(const Time &start, const Time &end) const = 0; //! Returns the data size in bytes if the current state would //! be written to a stream. Trimming has also to be taken into //! account while calculating the size. virtual size_t dataSize(bool withHeader = true) const = 0; //! Reads the packet from a streambuf and trims the data //! if possible to start and end. If maxBytes is greater //! than 0 then the record should not use more than this //! size of memory (in bytes). If not the complete record //! has been read, RS_Partial must be returned, RS_Complete //! otherwise. virtual ReadStatus get(std::streambuf &buf, int size, const Time &start = Time(), const Time &end = Time(), int maxBytes = -1) = 0; //! writes the packet to a streambuf and trims the data //! if possible to start and end virtual bool put(std::streambuf &buf, bool withHeader = true) const = 0; //! Returns the meta information of the data if supported virtual const Header *header() const = 0; //! Returns the start time of the record virtual Time startTime() const = 0; //! Returns the end time of the record virtual Time endTime() const = 0; //! Returns the packet type of the record virtual PacketType packetType() const = 0; /** * @brief Returns the data vector to be filled by the caller * @return The pointer to the internal buffer */ virtual Buffer *buffer() { return &_data; } /** * @brief Returns pointer to raw data. If the record * is compressed it will be uncompressed * @return The pointer to the raw data */ virtual Buffer *data() { return &_data; } protected: Buffer _data; }; typedef boost::shared_ptr DataRecordPtr; struct RawPacket { PacketDataHeader header; std::string SID[4]; std::vector data; DataRecord *record; }; struct MetaPacket { std::string SID[4]; PacketDataHeader packetDataHeader; DataRecord *record; DataRecord::Header recordHeader; Time startTime; Time endTime; Time timestamp; }; } } #endif