1
0
Fork 0

rx merging on sACN universe priority

This commit is contained in:
Kevin Matz 2021-08-02 10:09:14 -04:00
parent f9c01e5ad3
commit 4ce0bf73ea
8 changed files with 640 additions and 206 deletions

View File

@ -26,12 +26,24 @@
namespace DMX {
/**
*/
Universe::Universe() {
* @brief Universe::Universe
*/
Universe::Universe()
{
null_start_data_.fill(0);
}
/**
* @brief Universe::~Universe
*/
Universe::~Universe()
{
}
/**
Get value of a slot.

View File

@ -54,10 +54,11 @@ using DimmerData = std::array<uint8_t, 513>;
class Universe {
public:
Universe ();
virtual ~Universe ();
const DimmerData * data() const { return &null_start_data_; }
const uint8_t slot (const uint16_t) const;
const double rxRate();
virtual const DimmerData * data() const { return &null_start_data_; }
virtual uint8_t slot (const uint16_t) const;
virtual double rxRate();
void setValue (const uint16_t, const uint8_t);
void setValue (const uint16_t, const uint16_t, const uint8_t*);
@ -65,9 +66,11 @@ class Universe {
void setData (std::vector<uint8_t>);
void onData (const DataHandler);
protected:
std::vector<DataHandler> callbacks_;
private:
DimmerData null_start_data_;
std::vector<DataHandler> callbacks_;
std::queue<std::chrono::time_point<std::chrono::system_clock>> rx_times_;
void rx_timeout_(bool add_now = false);

View File

@ -44,6 +44,16 @@ Receiver::Receiver(UUID::uuid cid)
}
/**
* @brief Receiver::~Receiver
*/
Receiver::~Receiver()
{
for (auto& [_, universe] : universes_)
delete universe;
}
/**
* @brief Receiver::subscribe
* @param num
@ -51,7 +61,7 @@ Receiver::Receiver(UUID::uuid cid)
void Receiver::subscribe(const uint16_t num) {
if (universes_.count(num))
return;
universes_.emplace(num, new SACN::Universe());
universes_.emplace(num, new MergeProxyUniverse());
}
@ -60,10 +70,11 @@ void Receiver::subscribe(const uint16_t num) {
* @param num
*/
void Receiver::unsubscribe(const uint16_t num) {
if (!universes_.count(num))
return;
delete universes_.at(num);
universes_.erase(num);
// delete merging universe proxy
if (universes_.count(num)) {
delete universes_.at(num);
universes_.erase(num);
}
}
@ -177,7 +188,7 @@ void Receiver::dataFrameHandler(std::shared_ptr<DATA::Pdu> frame) {
if (!universes_.count(source->universe()))
return;
Universe * universe = universes_.at(source->universe());
auto universe = universes_.at(source->universe())->sourceUniverse(*source);
// 6.2.3 E1.31 Data Packet: Priority
// No priority outside the range of 0 to 200 shall be transmitted on
@ -199,7 +210,7 @@ void Receiver::dataFrameHandler(std::shared_ptr<DATA::Pdu> frame) {
// Any property values in an E1.31 Data Packet containing this bit
// shall be ignored.
if (source->isTerminated()) {
unsubscribe(source->universe());
universes_[source->universe()]->deleteSourceUniverse(*source);
return;
}
@ -230,13 +241,6 @@ void Receiver::dataFrameHandler(std::shared_ptr<DATA::Pdu> frame) {
/// TODO:: do something to break synchronization
}
// 6.2.3.1 Multiple Sources at Highest Priority
// It is possible for there to be multiple sources, all transmitting data at
// the highest currently active priority for a given universe. When this
// occurs, receivers must handle these sources in some way.
/// TODO: do something with merging and arbitration
// PDU data will be a block of DMP
auto block = PDU::Block<DMP::Pdu>();
block.readBlock(frame->stream(), frame);

View File

@ -37,6 +37,8 @@ class Receiver
{
public:
Receiver(UUID::uuid = UUID::uuid());
~Receiver();
virtual void subscribe(const uint16_t);
virtual void unsubscribe(const uint16_t);
Universe * universe(const uint16_t);
@ -62,7 +64,7 @@ protected:
void discoveryListHanlder(std::shared_ptr<EXTENDED::DISCOVERY::Pdu>);
private:
std::unordered_map <uint16_t, SACN::Universe *> universes_;
std::unordered_map<uint16_t, MergeProxyUniverse*> universes_;
std::vector<EXTENDED::DISCOVERY::Watcher> discoveryCallbacks_;
};

View File

@ -65,6 +65,36 @@ UniverseSource::UniverseSource(std::shared_ptr<DATA::Pdu> pdu)
};
/**
* @brief operator ==
* @param a
* @param b
* @return
*/
bool operator== (const UniverseSource& a, const UniverseSource& b)
{
return (std::hash<UniverseSource>{}(a) == std::hash<UniverseSource>{}(b));
}
/**
* @brief Universe::Universe
*/
Universe::Universe()
: DMX::Universe()
, synchronized_(false)
{
};
/**
* @brief Universe::~Universe
*/
Universe::~Universe()
{
}
/**
Set universe data from a DMP PDU from a UniverseSource.
*/
@ -75,7 +105,11 @@ void Universe::set(std::shared_ptr<DMP::Pdu> dmp,
// Receivers shall discard the packet if the received value is not 0xa1.
if (!dmp->header())
return;
auto type = (ACN::DMP::address_type*)dmp->header();
#if defined(RTTI_ENABLED)
auto type = dynamic_cast<ACN::DMP::address_type*>(dmp->header());
#else
auto type = static_cast<ACN::DMP::address_type*>(dmp->header());
#endif
if (!type->z_reserved) return; // needs to be true, but why?
if (type->relative) return;
if (type->type != ACN::DMP::ARRAY) return;
@ -85,27 +119,30 @@ void Universe::set(std::shared_ptr<DMP::Pdu> dmp,
// only act on the first property pair in the data
if (!dmp->data())
return;
auto data = (ACN::DMP::dmp_set_data*)dmp->data();
auto prop = data->properties.front();
auto pr = prop.first; // property range
auto pd = prop.second; // property data
#if defined(RTTI_ENABLED)
auto set_data = dynamic_cast<ACN::DMP::dmp_set_data*>(dmp->data());
#else
auto set_data = static_cast<ACN::DMP::dmp_set_data*>(dmp->data());
#endif
const auto& [range, data] = set_data->properties.front();
// 7.4 First Property Address
// Sources shall set the DMP Layer's First Property Address to 0x0000.
// Receivers shall discard the packet if the received value is not 0x0000.
if (pr.address != 0)
if (range.address != 0)
return;
// 7.5 Address Increment
// Sources shall set the DMP Layer's Address Increment to 0x0001.
// Receivers shall discard the packet if the received value is not 0x0001.
if (pr.incriment != 1)
if (range.incriment != 1)
return;
// 7.6 Property Value Count
// The DMP Layer's Property Value Count is used to encode the number of
// DMX512-A [DMX] Slots (including the START Code slot).
if (pr.count < 1 || pr.count > 513)
if (range.count < 1 || range.count > 513)
return;
setSource(source);
@ -113,7 +150,7 @@ void Universe::set(std::shared_ptr<DMP::Pdu> dmp,
// 7.7 Property Values (DMX512-A Data)
// The DMP Layer's Property values field is used to encode the
// DMX512-A [DMX] START Code and data.
DMX::Universe::setData(pd);
DMX::Universe::setData(data);
}
@ -126,4 +163,211 @@ void Universe::setSource(std::shared_ptr<UniverseSource> source)
source_ = source;
}
MergeProxyUniverse::MergeProxyUniverse()
: SACN::Universe()
{
}
MergeProxyUniverse::~MergeProxyUniverse()
{
for (auto& [_, universe] : sources_)
delete universe;
}
/**
* @brief MergeProxyUniverse::sources
* @return
*/
const std::vector<UniverseSource> MergeProxyUniverse::sources() const
{
std::vector<UniverseSource> keys;
for (const auto& [key, _] : sources_)
keys.push_back(key);
return keys;
}
/**
* @brief MergeProxyUniverse::sourceUniverse
* @return
*/
Universe* MergeProxyUniverse::sourceUniverse(const UniverseSource &src)
{
if (!hasSourceUniverse(src))
newSource_(src);
return sources_.at(src);
}
/**
* @brief MergeProxyUniverse::hasSourceUniverse
* @return
*/
bool MergeProxyUniverse::hasSourceUniverse(const UniverseSource& src) const
{
if (sources_.count(src))
return true;
return false;
}
/**
* @brief MergeProxyUniverse::hassources
* @return
*/
bool MergeProxyUniverse::hasSources() const
{
if (sources_.size())
return true;
return false;
}
/**
* @brief MergeProxyUniverse::deleteSourceUniverse
* @return
*/
void MergeProxyUniverse::deleteSourceUniverse(const UniverseSource& src)
{
if (sources_.count(src)) {
delete sources_.at(src);
sources_.erase(src);
}
}
/**
* @brief MergeProxyUniverse::addSourceUniverse
*/
void MergeProxyUniverse::addSourceUniverse(Universe* universe)
{
sources_.at(*universe->source()) = universe;
}
/**
* @brief MergeProxyUniverse::dataChangedNotifier
* @param universe
*/
void MergeProxyUniverse::dataChangedNotifier(DMX::Universe* dmx)
{
#if defined(RTTI_ENABLED)
auto sacn = static_cast<SACN::Universe*>(dmx);
#else
auto sacn = static_cast<SACN::Universe*>(dmx);
#endif
auto universe = dominant_();
if (!universe)
return;
if (sacn->source() == universe->source())
for (const auto &cb : callbacks_)
cb(this);
}
/**
* @brief MergeProxyUniverse::isSyncronized
* @return
*/
bool MergeProxyUniverse::isSyncronized() const
{
auto universe = dominant_();
if (!universe) return false;
return universe->isSyncronized();
}
/**
* @brief MergeProxyUniverse::source
* @return
*/
std::shared_ptr<UniverseSource> MergeProxyUniverse::source() const
{
auto universe = dominant_();
if (!universe) return nullptr;
return universe->source();
}
/**
* @brief MergeProxyUniverse::set
* @param pdu
* @param source
*/
void MergeProxyUniverse::set(std::shared_ptr<DMP::Pdu> pdu,
std::shared_ptr<UniverseSource> src)
{
if (!sources_.count(*src))
newSource_(*src);
sources_.at(*src)->set(pdu, src);
}
/**
* @brief MergeProxyUniverse::data
* @return
*/
const DMX::DimmerData * MergeProxyUniverse::data() const
{
auto universe = dominant_();
if (!universe) return nullptr;
return universe->data();
}
/**
* @brief MergeProxyUniverse::slot
* @param s
* @return
*/
uint8_t MergeProxyUniverse::slot(const uint16_t s) const
{
auto universe = dominant_();
if (!universe) return 0;
return universe->slot(s);
}
/**
* @brief MergeProxyUniverse::rxRate
* @return
*/
double MergeProxyUniverse::rxRate()
{
auto universe = dominant_();
if (!universe) return 0.0;
return universe->rxRate();
}
/**
* @brief MergeProxyUniverse::dominant_
* @return
*/
Universe* MergeProxyUniverse::dominant_() const
{
Universe* ret = nullptr;
for (auto& [_, uni] : sources_) {
if (uni->rxRate() < 1) // stale universes cannot be dominant
continue;
if (!ret || uni->source()->priority() > ret->source()->priority())
ret = uni;
}
return ret;
}
/**
* @brief MergeProxyUniverse::newSource_
* @param src
*/
void MergeProxyUniverse::newSource_(const UniverseSource &src)
{
sources_.emplace(src, new Universe());
sources_.at(src)->onData(std::bind(&SACN::MergeProxyUniverse::dataChangedNotifier,
this, std::placeholders::_1));
}
}; // SACN

View File

@ -28,13 +28,13 @@
#include "../dmx/universe.h"
#include "../uuid/uuid.h"
#include <memory>
#include <unordered_map>
#include <string>
namespace SACN {
/**
universe metadata
*/
* @brief The UniverseSource class
*/
class UniverseSource
{
public:
@ -53,6 +53,8 @@ public:
const bool isForced() const {return options_
& DATA::FORCE_SYNCHRONIZATION;}
friend bool operator== (const UniverseSource& a, const UniverseSource& b);
void setCID(UUID::uuid cid) { cid_ = cid; }
void setDescription(std::string desc) { description_ = desc; }
void setOptions(uint8_t o) { options_ = o; }
@ -68,21 +70,49 @@ private:
uint16_t sync_address_;
uint8_t options_;
};
} // SACN namespace
namespace std
{
template<>
/**
* @brief The hash struct specilizaton for SACN::UniverseSource
*/
struct hash<SACN::UniverseSource>
{
/**
* @brief operator ()
* @param src
* @return
*/
size_t operator()(SACN::UniverseSource const& src) const noexcept
{
size_t h1 = hash<string>{}(src.description());
size_t h2 = hash<UUID::uuid>{}(src.CID());
size_t h3 = hash<int>{}(src.priority());
size_t h = h1 ^ h2 ^ h3; // or use boost::hash_combine
return h;
}
};
} // std namespace
namespace SACN {
/**
universe data
*/
* @brief The Universe class
*/
class Universe
: public DMX::Universe
{
public:
Universe() : DMX::Universe(), synchronized_(false) {};
const bool isSyncronized() const {return synchronized_;};
std::shared_ptr<UniverseSource> source() const { return source_; }
Universe();
~Universe();
void set(std::shared_ptr<DMP::Pdu>, std::shared_ptr<UniverseSource>);
void setSource(std::shared_ptr<UniverseSource>);
virtual bool isSyncronized() const { return synchronized_; };
virtual std::shared_ptr<UniverseSource> source() const { return source_; }
virtual void set(std::shared_ptr<DMP::Pdu>, std::shared_ptr<UniverseSource>);
virtual void setSource(std::shared_ptr<UniverseSource>);
private:
bool synchronized_;
@ -90,4 +120,45 @@ private:
};
/**
* @brief The MergeProxyUniverse class
* 6.2.3.1 Multiple Sources at Highest Priority
* It is possible for there to be multiple sources, all transmitting data
* at the highest currently active priority for a given universe. When this
* occurs, receivers must handle these sources in some way.
*/
class MergeProxyUniverse
: public SACN::Universe
{
public:
MergeProxyUniverse();
~MergeProxyUniverse();
// Source universes:
const std::vector<UniverseSource> sources() const;
Universe* sourceUniverse(const UniverseSource&);
bool hasSourceUniverse(const UniverseSource&) const;
bool hasSources() const;
void deleteSourceUniverse(const UniverseSource&);
void addSourceUniverse(Universe *);
void dataChangedNotifier(DMX::Universe* universe);
// SACN::Universe overrides:
bool isSyncronized() const override;
std::shared_ptr<UniverseSource> source() const override;
void set(std::shared_ptr<DMP::Pdu>, std::shared_ptr<UniverseSource>) override;
void setSource(std::shared_ptr<UniverseSource>) override {};
// DMX::Universe Overrides:
const DMX::DimmerData *data() const override;
uint8_t slot(const uint16_t) const override;
double rxRate() override;
private:
std::unordered_map<UniverseSource, SACN::Universe*> sources_;
Universe* dominant_() const;
void newSource_(const UniverseSource&);
};
} // SACN namespace

View File

@ -32,9 +32,11 @@
namespace UUID {
/**
construct a NIL UUID
*/
uuid::uuid() {
* @brief uuid::uuid
*/
uuid::uuid()
: raw_(new uint8_t[16])
{
type_ = NIL;
version_ = VOID;
timestamp_ = 0;
@ -45,39 +47,63 @@ uuid::uuid() {
/**
create this UUID from a byte array
*/
void uuid::fromArray(const uint8_t * bytes) {
std::memcpy(raw_, bytes, sizeof(raw_));
setType();
switch (type_) {
case NCS:
setNCSFields();
break;
case RFC4122:
setRFC4122Fields();
break;
default:
break;
}
* @brief uuid::uuid
* @param other
*/
uuid::uuid(const uuid& other)
: raw_(new uint8_t[16])
{
type_ = other.type_;
version_ = other.version_;
timestamp_ = other.timestamp_;
clock_seq_ = other.clock_seq_;
node_ = other.node_;
setBytes();
}
/**
create this UUID from a C style char array
*/
* @brief uuid::~uuid
*/
uuid::~uuid()
{
delete[] raw_;
}
/**
* @brief uuid::fromArray
* @param bytes
*
* create this UUID from a byte array
*/
void uuid::fromArray(const uint8_t * bytes) {
std::memcpy(raw_, bytes, 16);
setFields();
}
/**
* @brief uuid::fromCstring
* @param cstr
*
* create this UUID from a C style char array
*/
void uuid::fromCstring(const char * cstr) {
fromString(std::string(cstr));
}
/**
create this UUID from a string representation
*/
* @brief uuid::fromString
* @param str
*
* create this UUID from a string representation
*/
void uuid::fromString(std::string str) {
// remove formating
if (str.front() == '{' && str.back() == '}')
str = str.substr(1, str.size() - 2);
str = str.substr(1, str.size() - 2);
str.erase(std::remove(str.begin(), str.end(), '-'), str.end());
if (str.length() != 32) return;
// fill buffer
@ -89,21 +115,27 @@ void uuid::fromString(std::string str) {
};
/*
output this UUID as a hex string
*/
/**
* @brief uuid::hex
* @return
*
* output this UUID as a hex string
*/
std::string uuid::hex() const {
std::ostringstream oss;
oss << std::hex;
for (uint8_t raw : raw_)
oss << std::setw(2) << std::setfill('0') << (int)raw;
for (int i = 0; i < 16; i++)
oss << std::setw(2) << std::setfill('0') << (int)raw_[i];
return oss.str();
}
/**
output this UUID as formated hex string
*/
* @brief uuid::string
* @return
*
* output this UUID as formated hex string
*/
std::string uuid::string() const {
std::string str = hex();
str.reserve(str.length() + 6);
@ -116,32 +148,36 @@ std::string uuid::string() const {
/**
output this UUID as a urn specified in RFC 4122
*/
* @brief uuid::urn
* @return
*
* output this UUID as a urn specified in RFC 4122
*/
std::string uuid::urn() const {
return "urn:uuid:" + string();
}
/**
make the raw bytes match the field contents
*/
* @brief uuid::setBytes
* make the raw bytes match the field contents
*/
void uuid::setBytes()
{
switch (type_) {
switch (type_) {
case NIL:
std::memset(raw_, 0, sizeof(raw_));
break;
std::memset(raw_, 0, 16);
break;
case NCS:
setNCSBytes();
break;
setNCSBytes();
break;
case RFC4122:
setRFC4122Bytes();
break;
setRFC4122Bytes();
break;
case MS:
break;
break;
case RESVERED:
break;
break;
}
}
@ -151,13 +187,13 @@ void uuid::setBytes()
*/
void uuid::setNCSBytes()
{
NCSFields fields;
fields.time = timestamp_;
fields.res = 0;
fields.family = version_;
fields.node = node_;
NCSFields fields;
fields.time = timestamp_;
fields.res = 0;
fields.family = version_;
fields.node = node_;
std::memcpy(raw_, &fields, sizeof(raw_));
std::memcpy(raw_, &fields, 16);
}
@ -167,23 +203,42 @@ void uuid::setNCSBytes()
*/
void uuid::setRFC4122Bytes()
{
RFC4122Fields fields;
fields.time_low = timestamp_;
fields.time_mid = timestamp_ >> 32;
fields.time_hi_version = timestamp_ >> 48;
RFC4122Fields fields;
fields.time_low = timestamp_;
fields.time_mid = timestamp_ >> 32;
fields.time_hi_version = timestamp_ >> 48;
fields.clock_seq_low = clock_seq_;
fields.clock_seq_hi_variant = clock_seq_ >> 8;
fields.clock_seq_low = clock_seq_;
fields.clock_seq_hi_variant = clock_seq_ >> 8;
fields.node_low = node_;
fields.node_high = node_ >> 16;
fields.node_low = node_;
fields.node_high = node_ >> 16;
std::memcpy(raw_, &fields, sizeof(raw_));
std::memcpy(raw_, &fields, 16);
// version
raw_[7] = (raw_[7] & 0x0f) | (version_ << 4);
// type
raw_[8] = (raw_[8] & 0b00111111) | (type_ << 6);
// version
raw_[7] = (raw_[7] & 0x0f) | (version_ << 4);
// type
raw_[8] = (raw_[8] & 0b00111111) | (type_ << 6);
}
/**
* @brief uuid::setFields
*/
void uuid::setFields()
{
setType();
switch (type_) {
case NCS:
setNCSFields();
break;
case RFC4122:
setRFC4122Fields();
break;
default:
break;
}
}
@ -192,23 +247,22 @@ void uuid::setRFC4122Bytes()
*/
void uuid::setNCSFields()
{
NCSFields fields;
std::memcpy(&fields, raw_, sizeof (raw_));
NCSFields fields;
std::memcpy(&fields, raw_, 16);
timestamp_ = fields.time;
version_ = fields.family;
node_ = fields.node;
timestamp_ = fields.time;
version_ = fields.family;
node_ = fields.node;
}
/**
populate data fields from byte array
*/
// TODO: Check endianness
* @brief uuid::setRFC4122Fields
*/
void uuid::setRFC4122Fields()
{
RFC4122Fields fields;
std::memcpy(&fields, raw_, sizeof(raw_));
std::memcpy(&fields, raw_, 16);
timestamp_ = fields.time_low;
timestamp_ |= (uint64_t)fields.time_mid << 32;
@ -243,8 +297,10 @@ void uuid::setRFC4122Fields()
/**
exctract the type from the raw bytes
*/
* @brief uuid::setType
*
* exctract the type from the raw bytes
*/
void uuid::setType() {
if ((raw_[8] >> 7) == 0b0) {
type_ = NCS;
@ -257,43 +313,41 @@ void uuid::setType() {
}
}
/**
compare to another UUID
*/
bool uuid::operator== (const uuid & other) const {
return std::memcmp(raw_, other.bytes(), sizeof(raw_));
* @brief uuid::operator =
* @param other
* @return
*/
uuid& uuid::operator=(const uuid& other)
{
if (this != &other) { // protect against invalid self-assignment
std::memcpy(raw_, other.raw_, 16);
setFields();
}
return *this;
}
/**
compare to another byte array
*/
bool uuid::operator== (const uint8_t * other) const {
if (sizeof(raw_) != sizeof(other))
return false;
return std::memcmp(raw_, other, sizeof(raw_));
* @brief operator ==
* @param a
* @param b
* @return
*/
bool operator== (const uuid& a, const uuid& b)
{
if (std::memcmp(a.raw_, b.raw_, 16) == 0)
return true;
return false;
}
/**
compare to another formatted C string
*/
bool uuid::operator== (const char* other) const {
return std::strcmp(string().c_str(), other);
}
/**
compare to another formatted std::string
*/
bool uuid::operator== (const std::string & other) const {
return string().compare(other);
}
/**
create this UUID as a Version 4 (RANDOM) UUID
*/
* @brief uuid::uuid4
*
* create this UUID as a Version 4 (RANDOM) UUID
*/
void uuid::uuid4() {
type_ = RFC4122;
version_ = RAND;

View File

@ -30,71 +30,99 @@
// RFC4122 A Universally Unique IDentifier (UUID) URN Namespace
namespace UUID {
/**
* @brief The Type enum
*/
enum Type {
NCS, // Reserved, NCS backward compatibility.
RFC4122, // The variant specified in this document.
MS, // Reserved, Microsoft Corporation backward compatibility
RESVERED, // Reserved for future definition.
NIL
};
/**
* @brief The RFC4122Version enum
*/
enum RFC4122Version {
VOID = 0b0000,
TIME = 0b0001, // The time-based version specified in this document.
DCE = 0b0010, // DCE Security version, with embedded POSIX UIDs.
MD5 = 0b0011, // The name-based version that uses MD5 hashing.
RAND = 0b0100, // The randomly or pseudo-randomly generated version.
SHA1 = 0b0101 // The name-based version that uses SHA-1 hashing.
};
/**
* @brief The Namespace enum
*/
enum Namespace {
DNS, // the name string is a fully-qualified domain name.
URL, // the name string is a URL.
OID, // the name string is an ISO OID.
X500 // the name string is an X.500 DN in DER or a text output format.
};
/**
* @brief The NCSFields struct
*/
struct NCSFields {
uint64_t time : 48;
uint16_t res;
uint8_t family;
uint64_t node : 56;
}__attribute__((packed));
/**
* @brief The RFC4122Fields struct
*/
struct RFC4122Fields {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_version;
uint8_t clock_seq_hi_variant;
uint8_t clock_seq_low;
uint16_t node_low;
uint32_t node_high;
}__attribute__((packed));
// extern const std::string NAMESPACE_DNS;
// extern const std::string NAMESPACE_URL;
// extern const std::string NAMESPACE_OID;
// extern const std::string NAMESPACE_X500;
/**
* @brief The uuid class
*/
class uuid {
public:
enum Type {
NCS, // Reserved, NCS backward compatibility.
RFC4122, // The variant specified in this document.
MS, // Reserved, Microsoft Corporation backward compatibility
RESVERED, // Reserved for future definition.
NIL
};
enum RFC4122Version {
VOID = 0b0000,
TIME = 0b0001, // The time-based version specified in this document.
DCE = 0b0010, // DCE Security version, with embedded POSIX UIDs.
MD5 = 0b0011, // The name-based version that uses MD5 hashing.
RAND = 0b0100, // The randomly or pseudo-randomly generated version.
SHA1 = 0b0101 // The name-based version that uses SHA-1 hashing.
};
enum Namespace {
DNS, // the name string is a fully-qualified domain name.
URL, // the name string is a URL.
OID, // the name string is an ISO OID.
X500 // the name string is an X.500 DN in DER or a text output format.
};
struct NCSFields {
uint64_t time : 48;
uint16_t res;
uint8_t family;
uint64_t node : 56;
}__attribute__((packed));
struct RFC4122Fields {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_version;
uint8_t clock_seq_hi_variant;
uint8_t clock_seq_low;
uint16_t node_low;
uint32_t node_high;
}__attribute__((packed));
// constructor
uuid();
uuid(const uuid& other);
uuid(const uint8_t * raw) : uuid() { fromArray(raw); };
uuid(const char * cstr) : uuid() { fromCstring(cstr); };
uuid(std::string str) : uuid() { fromString(str); };
~uuid();
// accessors
const Type type() const { return type_; };
const uint16_t version() const { return version_; };
const uint64_t time() const { return timestamp_; };
const uint16_t sequence() const { return clock_seq_; };
const uint64_t node() const { return node_; };
const uint8_t * bytes() const { return raw_; };
Type type() const { return type_; };
uint16_t version() const { return version_; };
uint64_t time() const { return timestamp_; };
uint16_t sequence() const { return clock_seq_; };
uint64_t node() const { return node_; };
const uint8_t* bytes() const { return raw_; };
// comparitor overload
bool operator== (const uuid &) const;
bool operator== (const uint8_t *) const;
bool operator== (const char *) const;
bool operator== (const std::string &) const;
// operator overloads
uuid& operator= (const uuid& other);
friend bool operator== (const uuid& a, const uuid& b);
// typecast overload
operator const uint8_t * () const { return raw_; };
operator const uint8_t* () const { return raw_; };
operator const std::string () const { return string(); };
// output
@ -103,13 +131,13 @@ public:
std::string urn() const; // 'urn:uuid:12345678-1234-5678-1234-567812345678'
// creators
virtual void uuid1(uint64_t node, uint16_t clock_seq) {};
virtual void uuid3(Namespace, std::string) {};
// virtual void uuid1(uint64_t node, uint16_t clock_seq) {};
// virtual void uuid3(Namespace, std::string) {};
virtual void uuid4(); // very low quality of random
virtual void uuid5(Namespace, std::string) {};
// virtual void uuid5(Namespace, std::string) {};
private:
uint8_t raw_[16];
uint8_t* raw_;
Type type_;
uint16_t version_;
uint64_t timestamp_;
@ -125,14 +153,30 @@ private:
void setNCSBytes();
void setRFC4122Bytes();
void setFields();
void setNCSFields();
void setRFC4122Fields();
}; // uuid
};
} // namespace UUID
// extern const std::string NAMESPACE_DNS;
// extern const std::string NAMESPACE_URL;
// extern const std::string NAMESPACE_OID;
// extern const std::string NAMESPACE_X500;
}; // UUID
namespace std
{
template<>
/**
* @brief The hash struct specialization for UUID::uuid
*/
struct hash<UUID::uuid>
{
/**
* @brief operator ()
* @param id
* @return
*/
size_t operator()(UUID::uuid const& id) const noexcept
{
return hash<string>{}(id.hex());
}
};
} // namespace std