You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
10 KiB
C++
421 lines
10 KiB
C++
/***************************************************************************
|
|
* 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 <gempa/caps/api.h>
|
|
|
|
#include <gempa/caps/endianess.h>
|
|
#include <gempa/caps/datetime.h>
|
|
|
|
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
#include <stdint.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
|
|
|
|
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<char> 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<DataRecord> DataRecordPtr;
|
|
|
|
|
|
struct RawPacket {
|
|
PacketDataHeader header;
|
|
std::string SID[4];
|
|
std::vector<char> data;
|
|
DataRecord *record;
|
|
};
|
|
|
|
struct MetaPacket {
|
|
std::string SID[4];
|
|
PacketDataHeader packetDataHeader;
|
|
DataRecord *record;
|
|
DataRecord::Header recordHeader;
|
|
Time startTime;
|
|
Time endTime;
|
|
Time timestamp;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|