remove libESTA as directory, now a submodule

This commit is contained in:
Kevin Matz 2021-05-27 11:07:23 -04:00
parent d1fcb08bd8
commit e3f3fa5b45
34 changed files with 0 additions and 3164 deletions

View File

@ -1,44 +0,0 @@
# LibESTA
This collection of libraries serve as a testbed for ESTA sponsored ANSI standards on embedded platforms.
## Supported Standards
| Protocol Name | Standard | Implementation Status |
| :- | :-: | :-: |
| 0 to 10 V Analog Control | E1.3 | |
| USITT DMX512-A | E1.11 | Data Abstraction |
| ACN Root Layer Protocol (RLP) | E1.17 | Rx |
| ACN Session Data Transport Protocol (SDT) | E1.17 | |
| ACN Device Management Protocol (DMP) | E1.17 | Limited |
| ACN Device Description Language (DDL) | E1.17 | |
| EPI 10 - Autogeneration of Multicast Address on IPv4 Networks | E1.17 | |
| EPI 11 - Retrieval of Device Descriptions from DMP Devices on IPv4 Networks | E1.17 | |
| EPI 12 - ACN on Homogeneous Ethernet Networks | E1.17 | |
| EPI 13 - Allocation of Internet Protocol Version 4 Addresses to ACN Hosts | E1.17 | |
| EPI 15 - ACN Allocation of Multicast Addresses on IPv4 Networks | E1.17 | |
| EPI 16 - ESTA Registered Names and Identifiers | E1.17 | |
| EPI 17 - ACN Root Layer Protocol Operation on UDP | E1.17 | Rx |
| EPI 18 - Operation of SDT on UDP Networks | E1.17 | |
| EPI 19 - ACN Discovery on IP Networks | E1.17 | |
| EPI 20 - MTU Size for ACN on IPv4 Networks | E1.17 | |
| EPI 22 - DDL Core Modules for ACN Devices | E1.17 | |
| Remote Device Management (RDM) | E1.20 | |
| EPI 23 - Device Identification Subdevice | E1.30-1 | |
| EPI 25 - Time Reference in ACN Systems Using SNTP and NTP | E1.30-3 | |
| EPI 26 - DDL Extensions for DMX and RDM Devices | E1.30-4 | |
| EPI 32 - Identification of Draft DDL Modules | E1.30-10 | |
| EPI 33 - ACN RLP Operation on TCP | E1.30-11 | |
| Streaming ACN (sACN) | E1.31 | Data |
| RDMNet | E1.33 | |
| RDM Dimmer Message Sets | E1.37-1 | |
| RDM IPv4 & DNS Configuration Messages | E1.37-2 | |
| RDM Gateway & Splitter Configuration Messages | E1.37-7 | |
### Dependent Protocols
| Protocol Name | Standard | Referenced By | Implementation Status |
| :- | :-: |:-: | :-: |
|UUID Universally Unique Identifier | RFC 4122 | RLP, DDL | Partial |
|Service Location Protocol (SLP) | RFC 2609 | EPI 19 | |
|Trivial File Transfer Protocol (TFTP) | RFC 1350 | EPI 25 | |

View File

@ -1,35 +0,0 @@
# Library for E1.17 ACN
## `Architecture for Control Networks`
## Top level include
Include `acn.h` for full protocol support.
> ```#include "acn.h"```
## Logical components
### Protocol Handling
* ACN Architecture
* `pdu.h`: [`ACN::PDU`]
* `rlp.h`: [`ACN::RLP`]
* Device Management Protocol
* `dmp.h`: [`ACN::DMP`]
* Session Data Transport
* `sdt.h`: [`ACN::SDT`]
### EPI Support
* EPI 17. ACN Root Layer Protocol
Operation on UDP
* `rlp-udp.h`: [`ACN::RLP::UDP`]
* EPI 18. Operation of SDT on UDP Networks
* `sdt-udp.h`: [`ACN::SDT::UDP`]
* EPI 33. ACN Root Layer Protocol Operation on TCP
* `rlp-tcp.h`: [`ACN::RLP::TCP`]

View File

@ -1,60 +0,0 @@
/*
acn.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "appliance.h"
#include "component.h"
#include "dmp.h"
#include "pdu.h"
#include "rlp.h"
#include "rlp-tcp.h"
#include "rlp-udp.h"
#include "sdt.h"
#include "sdt-udp.h"
// ANSI E1.17- 2015, Architecture for Control Networks
namespace ACN {
// EPI 16 Protocol Identifier Database
// from https://tsp.esta.org/tsp/working_groups/CP/epi16ids.php
// as of 1/14/21
// Session Data Transport Protocol
static const uint32_t PLASA_SDT = 0x00000001;
// Device Management Protocol
static const uint32_t PLASA_DMP = 0x00000002;
// Lightweight streaming protocol for transport of DMX512
static const uint32_t PLASA_E1_31 = 0x00000004;
// RDMnet
static const uint32_t PLASA_E1_33 = 0x00000005;
// Empty data used for health checking connections in E1.33
static const uint32_t PLASA_NULL = 0x00000006;
// Open Lighting Architecture
static const uint32_t OpenLightingProject_OLA = 0x00000007;
// Extended functionality for sACN
static const uint32_t PLASA_E1_31_EXTENDED = 0x00000008;
// E1.59 Object Transform Protocol (OTP)
const static uint32_t ESTA_OTP = 0x00000009;
} // ACN

View File

@ -1,152 +0,0 @@
/*
appliance.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "appliance.h"
#include "dmp.h"
#include "sdt.h"
#include "rlp.h"
#include "rlp-udp.h"
#include "rlp-tcp.h"
namespace ACN {
Appliance::Appliance(UUID::uuid cid)
: Component(cid)
{
registerRlpVectorHandler(SDT::SDT_PROTOCOL_ID,
std::bind(&Appliance::rootSdtHandler, this,
std::placeholders::_1));
registerRlpVectorHandler(DMP::DMP_PROTOCOL_ID,
std::bind(&Appliance::rootDmpHandler, this,
std::placeholders::_1));
};
/**
EPI 17
*/
void Appliance::UdpStreamHandler(PDU::Stream stream) {
// verify the UDP preamble
RLP::UDP::preamble_t preamble(stream);
// Implementations shall check the ACN Packet Identifier and preamble size.
if (!preamble)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
// implementations shall compute the size and position of the PDU block from
// the preamble size and postamble size provided. ... ignoring any extra
// octets in the preamble or postamble.
for(int i = RLP::UDP::PREAMBLE_MINIMUM_SIZE; i < preamble.length; i++)
stream->read8();
if (!stream->good())
return;
auto block = PDU::readBlock<RLP::Pdu>(stream);
if (stream->fail())
return;
for(auto root : *block) {
RlpReceiver(root);
}
}
/**
EPI 33
*/
void Appliance::TcpStreamHandler(PDU::Stream stream) {
// verify the TCP preamble
RLP::TCP::preamble_t preamble(stream);
// implementations shall check the ACN Packet Identifier. If the ACN Packet
// Identifier is not correct the receiver shall close the connection.
if (!preamble)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
if (!stream->good())
return;
auto block = PDU::readBlock<RLP::Pdu>(stream);
if (stream->fail())
return;
for(auto root : *block) {
RlpReceiver(root);
}
}
/**
Dispatch a recieved RLP PDU to the appropriate vector handlers.
*/
void Appliance::RlpReceiver(std::shared_ptr<RLP::Pdu> root) {
if (!rlp_vectors_.count(root->vector()))
return;
for(auto handler : rlp_vectors_[root->vector()]) {
handler(root);
}
}
/**
Add callback handler for a given RLP vector.
*/
void Appliance::registerRlpVectorHandler(uint32_t vect,
PDU::Handler<RLP::Pdu> handle) {
rlp_vectors_[vect].push_back(handle);
}
/**
Deregister RLP protocol handlers for the given vector.
*/
void Appliance::deregisterRlpVector(uint32_t vect) {
rlp_vectors_.erase(vect);
}
/**
Deregister _ALL_ RLP protocol handlers.
*/
void Appliance::deregisterRlpVector() {
rlp_vectors_.clear();
}
/**
*/
void Appliance::rootSdtHandler(std::shared_ptr<RLP::Pdu> rlp) {
}
/**
*/
void Appliance::rootDmpHandler(std::shared_ptr<RLP::Pdu> rlp) {
}
}; // ACN

View File

@ -1,79 +0,0 @@
/*
appliance.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "component.h"
#include "rlp.h"
#include "sdt.h"
#include "pdu.h"
#include "../uuid/uuid.h"
#include <map>
#include <memory>
#include <vector>
// appliance: In DDL an appliance is a piece of equipment described by a root device and all its children and descendents. In DMP systems an appliance corresponds to a component that exposes one or more devices (since the rules require that all devices are descendants of a single root device). See also root device.
// component: The process, program or application corresponding to a single ACN endpoint. All messages in ACN are sent and received by a component. See [Arch] for a more complete definition.
// root device: An instance of a device described in DDL that has no parent device. See also appliance.
namespace ACN {
class Appliance
: public Component
{
public:
Appliance(UUID::uuid = UUID::uuid());
protected:
// EPI 17
virtual void UdpStreamHandler(PDU::Stream);
// EPI 33
virtual void TcpStreamHandler(PDU::Stream);
void RlpReceiver(std::shared_ptr<RLP::Pdu>);
void registerRlpVectorHandler(uint32_t, PDU::Handler<RLP::Pdu>);
void deregisterRlpVector(uint32_t);
void deregisterRlpVector();
// process SDT frames
virtual void rootSdtHandler(std::shared_ptr<RLP::Pdu>);
// SDT 4.4 SDT Base Layer Messages
// Join, Get Sessions, and Sessions are ad-hoc messages, that is, they are
// not sent within channels. These messages identify their intended recipient
// by CID.
virtual void JoinSession() {};
virtual void GetSessions() {};
virtual void Sessions() {};
// process DMP frames
virtual void rootDmpHandler(std::shared_ptr<RLP::Pdu>);
private:
std::map<uint32_t, std::vector<PDU::Handler<RLP::Pdu>>> rlp_vectors_;
std::vector<std::shared_ptr<SDT::Session>> sessions_;
};
}; // ACN

View File

@ -1,41 +0,0 @@
/*
component.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "../uuid/uuid.h"
namespace ACN {
// 2.1. ACN Components and Component Identifiers (CIDs)
class Component {
public:
Component(UUID::uuid cid = UUID::uuid()) { cid_ = cid; };
const UUID::uuid cid() const { return cid_; };
private:
UUID::uuid cid_;
};
}; // ACN

View File

@ -1,116 +0,0 @@
/*
dmp.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "dmp.h"
namespace ACN {
namespace DMP {
address_type::address_type(uint8_t val) {
z_reserved = (val >> 7) & 0b1;
relative = (val >> 6) & 0b1;
type = (data_type)((val >> 4) & 0b11);
x_reserved = (val >> 2) & 0b11;
width = (address_length)(val & 0b11);
}
range::range(PDU::Stream stream, data_type t, address_length l) {
address = read(stream, l);
if (t == SINGLE) return;
incriment = read(stream, l);
count = read(stream, l);
}
uint32_t range::read(PDU::Stream stream, address_length length) {
switch (length) {
case ONE:
return stream->read8();
case TWO:
return stream->read16();
case FOUR:
return stream->read32();
default:
return 0;
}
}
Pdu::Pdu(PDU::Stream stream)
: PDU::Pdu(stream, 1) // vectors are 1 octet
{
if (stream->fail()) return;
if (!buffer_->good()) return;
if (flags_.hasHeader)
setHeader(new address_type(buffer_->read8()));
if (flags_.hasData) {
switch(vector()) {
case SET_PROPERTY:
readSetData();
break;
default:
break;
}
}
}
void Pdu::readSetData() {
// header may be inherited. check that one exists
if (!header()) {
buffer_->setstate(buffer_->rdstate() | std::ios_base::failbit);
return;
}
auto header = (address_type*)this->header();
auto data = new dmp_set_data();
while(buffer_->good()) {
// Property Address
range pr(buffer_, header->type, header->width);
if (!buffer_->good() || pr.count * pr.incriment > buffer_->available()) {
buffer_->setstate(buffer_->rdstate() | std::ios_base::failbit);
break;
}
// Property Data
std::vector<uint8_t> pd;
pd.resize(pr.address, 0);
for (uint32_t i = 0; i < pr.count * pr.incriment; i ++)
pd.push_back(buffer_->read8());
// Property Fields
set_property fields(pr, pd);
data->properties.push_back(fields);
//set EOF if buffer insufficient for another property range
if (buffer_->available() < header->width * (header->type == SINGLE? 1 : 3))
buffer_->setstate(buffer_->rdstate() | std::ios_base::eofbit);
}
setData(data);
}
} // DMP
} // ACN

View File

@ -1,121 +0,0 @@
/*
dmp.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <memory>
#include <vector>
#include "pdu.h"
// Architecture for Control Networks Device Management Protocol
namespace ACN {
namespace DMP {
using std::uint8_t;
using std::uint32_t;
using std::vector;
using std::pair;
using PDU::Block;
// 5.1.4 Address and Data Types
enum data_type {
SINGLE = 0b00, // 0
RANGE = 0b01, // 1
ARRAY = 0b10, // 2
SERIES = 0b11 // 3
};
enum address_length {
ONE = 0b00, // 0
TWO = 0b01, // 1
FOUR = 0b10, // 2
ZERO = 0b11 // 3 (reserved)
};
struct address_type : PDU::pdu_header {
bool z_reserved : 1; // Z
bool relative : 1; // R
data_type type : 2; // D1, D0
uint8_t x_reserved : 2; // X1, X0
address_length width : 2; // A1, A0
address_type(uint8_t);
};
// 5.1.5
struct range {
uint32_t address;
uint32_t incriment;
uint32_t count;
range() {};
range(PDU::Stream, data_type, address_length);
private:
uint32_t read(PDU::Stream, address_length);
};
typedef pair<range, vector<uint8_t>> set_property;
struct dmp_set_data : PDU::pdu_data {
vector<set_property> properties;
};
// 7 Response Messages
enum failure_reason {
NONSPECIFIC = 1, // Non-specific or non-DMP reason.
NOT_PROPERTY = 2, // The address does not correspond to a property.
WRITE_ONLY = 3, // The propertys value may not be read.
NOT_WRITABLE = 4, // The propertys value may not be written.
DATA_ERROR = 5, // The data does not correspond to the property.
SUBSCIRPTION_NOT_SUPPORTED = 10, // Subscriptions on the specified property are not supported by the device.
NO_SUBSCRIPTIONS_SUPPORTED = 11, // Subscriptions not supported on any property.
INSUFFICIENT_RESOURCES = 12, // The component cannot support more subscriptions due to resource limitations
UNAVAILABLE = 13 // The propertys value is not available due to restrictions imposed by device specific functionality (e.g., access permission mechanisms).
};
// 13.1 Protocol Codes
static const uint32_t DMP_PROTOCOL_ID = 2; // PDU protocol value
// 13.2 Message Codes
static const uint8_t GET_PROPERTY = 1;
static const uint8_t SET_PROPERTY = 2;
static const uint8_t GET_PROPERTY_REPLY = 3;
static const uint8_t EVENT = 4;
static const uint8_t SUBSCRIBE = 7;
static const uint8_t UNSUBSCRIBE = 8;
static const uint8_t GET_PROPERTY_FAIL = 9;
static const uint8_t SET_PROPERTY_FAIL = 10;
static const uint8_t SUBSCRIBE_ACCEPT = 12;
static const uint8_t SUBSCRIBE_REJECT = 13;
static const uint8_t SYNC_EVENT = 17;
class Pdu
: public PDU::Pdu
{
public:
Pdu(PDU::Stream);
private:
void readSetData();
};
} // DMP
} // ACN

View File

@ -1,177 +0,0 @@
/*
pdu.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "pdu.h"
#include <cmath>
namespace ACN {
namespace PDU {
Pdu::Pdu(Stream stream, size_t vector_size)
: flags_(stream->peek())
{
header_ = 0;
data_ = 0;
parent_ = 0;
inherit_ = 0; // pointer to previous PDU in block
// read length and vector off of the stream
// abort if the remaining PDU length isn't available
if (stream->available() < (flags_.hasLength ? 3 : 2)) {
stream->setstate(stream->rdstate() | std::ios_base::failbit);
return;
}
readLength(stream);
if (!length_ || length_ > std::pow(2, (8 * (flags_.hasLength ? 3 : 2)) - 4)) {
stream->setstate(stream->rdstate() | std::ios_base::failbit);
return;
}
// length includes the flags, length, and vector
// calculate the remaining length of the PDU
int len = length_ - (flags_.hasLength ? 3 : 2);
// abort if the remaining PDU length isn't available
if (!stream->good() || stream->available() < len) {
stream->setstate(stream->rdstate() | std::ios_base::failbit);
return;
}
// create a stream buffer for the header and data
buffer_ = Stream(new pdu_stream(stream->data(), len));
if (buffer_->available() != len) {
stream->setstate(stream->rdstate() | std::ios_base::failbit);
return;
}
// fast-forward the input stream
for (int i = 0; i < len; i++)
stream->get();
if (!stream->available())
stream->setstate(stream->rdstate() | std::ios_base::eofbit);
if (flags_.hasVector)
readVector(vector_size);
}
Pdu::~Pdu() {
if (header_) delete header_;
if (data_) delete data_;
}
const uint32_t Pdu::vector() {
if (flags_.hasVector)
return vector_;
if (inherit_ != nullptr)
return inherit_->vector();
return 0;
}
pdu_header * Pdu::header() {
if (flags_.hasHeader)
return header_;
if (inherit_ != nullptr)
return inherit_->header();
return 0;
}
pdu_data * Pdu::data() {
if (flags_.hasData)
return data_;
if (inherit_ != nullptr)
return inherit_->data();
return 0;
}
void Pdu::readLength(Stream stream) {
length_ = stream->read16() & 0x0fff; // high 4 bytes are flags
if (flags_.hasLength)
length_ = (length_ << 8 ) | stream->read8();
}
void Pdu::readVector(uint8_t vector_size) {
vector_ = 0;
for (int o = vector_size - 1; o >= 0; o--)
vector_ |= (buffer_->read8() << (8 * o));
}
pdu_flags::pdu_flags(uint8_t val) {
hasLength = (val >> 7) & 0b1;
hasVector = (val >> 6) & 0b1;
hasHeader = (val >> 5) & 0b1;
hasData = (val >> 4) & 0b1;
};
uint8_t pdu_stream::read8() {
uint8_t ret = 0;
if (available() < (int)sizeof(ret)) {
setstate(rdstate() | std::ios_base::failbit);
return 0;
}
ret = get();
if (!available())
setstate(rdstate() | std::ios_base::eofbit);
return ret;
}
uint16_t pdu_stream::read16() {
uint16_t ret = 0;
if (available() < (int)sizeof(ret)) {
setstate(rdstate() | std::ios_base::failbit);
return 0;
}
ret |= get() << 8;
ret |= get();
if (!available())
setstate(rdstate() | std::ios_base::eofbit);
return ret;
}
uint32_t pdu_stream::read32() {
uint32_t ret = 0;
if (available() < (int)sizeof(ret)) {
setstate(rdstate() | std::ios_base::failbit);
return 0;
}
ret |= get() << 24;
ret |= get() << 16;
ret |= get() << 6;
ret |= get();
if (!available())
setstate(rdstate() | std::ios_base::eofbit);
return ret;
}
} // PDU
} // ACN

View File

@ -1,171 +0,0 @@
/*
pdu.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <functional>
#include <istream>
#include <memory>
#include <vector>
namespace ACN {
namespace PDU {
using std::uint8_t;
using std::uint16_t;
using std::uint32_t;
using std::vector;
using std::shared_ptr;
// 2.4.1. Flags
// Flags is a 4-bit field containing flags L, V, H and D which declare how the PDU is packed.
struct pdu_flags {
bool hasLength : 1;
bool hasVector : 1;
bool hasHeader : 1;
bool hasData : 1;
pdu_flags(uint8_t);
};
// MAYBE: remove virtuals?
// Arduino doen't enable RTTI for run-time polymorphism.
struct pdu_header { virtual ~pdu_header() {} };
struct pdu_data { virtual ~pdu_data() {} };
/**
Memory buffer of uint8_t data.
*/
class pdu_buffer
: public std::basic_streambuf<uint8_t>
{
public:
pdu_buffer(uint8_t * p, size_t l) { setg(p, p, p + l); };
uint8_t * cur_ptr() { return gptr(); };
};
/**
Input stream of nested PDU
*/
class pdu_stream
: public std::basic_istream<uint8_t>
{
public:
pdu_stream(uint8_t * p, size_t l)
: std::basic_istream<uint8_t>(&_buffer)
, _buffer(p, l) { rdbuf(&_buffer); }
uint32_t available() { return _buffer.in_avail(); }
uint8_t * data() { return _buffer.cur_ptr(); };
uint8_t read8 ();
uint16_t read16();
uint32_t read32();
private:
pdu_buffer _buffer;
};
using Stream = shared_ptr<pdu_stream>;
/**
Base class PDU
All PDU share common structure of:
flags, length, vector,
and protocol specific header/data.
Flag values indicate if lenght, vector, header or data
are present in the PDU, or if they should be inherited from the
preceding PDU.
*/
class Pdu {
public:
Pdu(Stream, size_t vector_size);
~Pdu();
// getters
const pdu_flags flags() {return flags_;}
const uint32_t length() {return length_;}
const uint32_t vector(); // may inherit
pdu_header * header(); // may inherit
pdu_data * data(); // may inherit
shared_ptr<Pdu> parent() {return parent_;}
Stream buffer() {return buffer_;}
// setters
void setParent (shared_ptr<Pdu> pdu) {parent_ = pdu;}
void setInherit(shared_ptr<Pdu> pdu) {inherit_ = pdu;}
protected:
pdu_flags flags_;
uint32_t length_;
uint32_t vector_;
shared_ptr<Pdu> parent_;
shared_ptr<Pdu> inherit_;
Stream buffer_;
// private setters
void setHeader (pdu_header * h) {header_ = h;}
void setData (pdu_data * d) {data_ = d;}
private:
pdu_header * header_;
pdu_data * data_;
void readLength(Stream);
void readVector(uint8_t);
};
template <typename T>
using Handler = std::function<void(std::shared_ptr<T>)>;
template <typename T>
using Block = std::shared_ptr<std::vector<std::shared_ptr<T>>>;
/**
Template creator of a PDU Block.
@param std::shared_ptr<PDU::pdu_stream> The stream to read from.
@return std::shared_ptr<std::vector<std::shared_ptr<T>>> A block of PDU
*/
template<typename T>
Block<T> readBlock(Stream buffer, shared_ptr<PDU::Pdu> parent = 0) {
auto block = Block<T>(new vector<shared_ptr<T>>);
while(buffer->good()) {
shared_ptr<T> pdu(new T(buffer));
if (buffer->fail()) // stream failed during pdu constructor
break;
if (pdu->buffer()->fail()) // pdu buffer errors
continue;
if (parent != 0) // set parent
pdu->setParent(parent);
if (!block->empty()) // set inheritee
pdu->setInherit(block->back());
block->push_back(pdu); // add to block
}
return block;
}
} // PDU
} // ACN

View File

@ -1,56 +0,0 @@
/*
rlp-tcp.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "rlp-tcp.h"
#include <cstring>
namespace ACN {
namespace RLP {
namespace TCP {
preamble_t::preamble_t(PDU::Stream stream) {
stream->read(acn_id, sizeof(acn_id));
if (stream->gcount() != 12)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
length = stream->read32();
}
/*
Validate compliance with ACN EPI 33. ACN Root Layer Protocol Operation on TCP
4.2. Reception
*/
preamble_t::operator bool () {
// 2. Preamble Format: The ACN Packet Identifier shall be the text string
// “ASC-E1.17\0\0\0” encoded in [ASCII].
if (memcmp(acn_id, ACN_PACKET_IDENTIFIER, 12))
return false;
return true;
}
} // TCP
} // RLP
} // ACN

View File

@ -1,55 +0,0 @@
/*
rlp-tcp.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include "rlp.h"
#include "pdu.h"
// EPI 33. ACN Root Layer Protocol Operation on TCP
namespace ACN {
namespace RLP {
namespace TCP {
// 3. Frame Preamble Format
struct preamble_t {
uint8_t acn_id[12]; // 3.1 Packet Identifier
uint32_t length; // 3.2 PDU Block Size
preamble_t(PDU::Stream);
operator bool();
};
// 3.1 Packet Identifier
// The ACN Packet Identifier shall be the text string
// “ASC-E1.17\0\0\0” encoded in [ASCII].
static constexpr uint8_t ACN_PACKET_IDENTIFIER[] = { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 };
// 3.2 PDU Block Size
static const uint32_t INDEFINITE = 0xffffffff;
} // TCP
} // RLP
} // ACN

View File

@ -1,62 +0,0 @@
/*
rlp-udp.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "rlp-udp.h"
#include <cstring>
namespace ACN {
namespace RLP {
namespace UDP {
preamble_t::preamble_t(PDU::Stream stream) {
length = stream->read16();
postamble_size = stream->read16();
stream->read(acn_id, 12);
if (stream->gcount() != 12)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
}
/*
Validate compliance with ACN EPI 17: ACN Root Layer Protocol on UDP
4.2. Reception
*/
preamble_t::operator bool () {
// 2. Preamble Format: The preamble size includes both size fields so the
// minimum value for preamble size is 16 (octets).
if (length < PREAMBLE_MINIMUM_SIZE)
return false;
// 2. Preamble Format: The ACN Packet Identifier shall be the text string
// “ASC-E1.17\0\0\0” encoded in [ASCII].
if (memcmp(acn_id, ACN_PACKET_IDENTIFIER, 12))
return false;
return true;
}
} // UDP
} // RLP
} // ACN

View File

@ -1,59 +0,0 @@
/*
rlp-udp.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include "rlp.h"
#include "pdu.h"
// ACN EPI 17. ACN Root Layer Protocol Operation on UDP
namespace ACN {
namespace RLP {
namespace UDP {
using std::uint8_t;
using std::uint16_t;
// The ACN Packet Identifier shall be the text string
// “ASC-E1.17\0\0\0” encoded in [ASCII].
static constexpr uint8_t ACN_PACKET_IDENTIFIER[] = { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 };
// 2. Preamble Format: The preamble size includes both size fields so the
// minimum value for preamble size is 16 (octets).
static const uint8_t PREAMBLE_MINIMUM_SIZE = 16;
// 2. Preamble Format
struct preamble_t {
uint16_t length;
uint16_t postamble_size;
uint8_t acn_id[12];
preamble_t(PDU::Stream);
operator bool();
};
} // UDP
} // RLP
} // ACN

View File

@ -1,52 +0,0 @@
/*
rlp.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "rlp.h"
namespace ACN {
namespace RLP {
rlp_header::rlp_header(PDU::Stream stream)
: PDU::pdu_header()
, cid()
{
uint8_t buf[16];
stream->read(buf, 16);
if (stream->gcount() != 16)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
cid = UUID::uuid(buf);
}
Pdu::Pdu(PDU::Stream stream)
: ACN::PDU::Pdu(stream, 4)
{
if (stream->fail()) return;
if (!buffer_->good()) return;
if (flags_.hasHeader)
setHeader(new rlp_header(buffer_));
}
} // RLP
} // ACN

View File

@ -1,50 +0,0 @@
/*
rlp.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <memory>
#include "pdu.h"
#include "../uuid/uuid.h"
namespace ACN {
namespace RLP {
// 2.6.1.2.2. Header Field in Root Layer PDUs
// The Header field in Root Layer PDUs shall contain the CID of the component
// that generated the PDU (the Source CID).
struct rlp_header : PDU::pdu_header {
UUID::uuid cid;
rlp_header(PDU::Stream);
};
class Pdu
: public PDU::Pdu
{
public:
Pdu(PDU::Stream);
};
} // RLP
} // ACN

View File

@ -1,59 +0,0 @@
/*
sdt-udp.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
// ACN EPI 18 - Operation of SDT on UDP Networks
namespace ACN {
namespace SDT {
namespace UDP {
// 3 Address Specification
struct address_t {
uint8_t type;
uint16_t udp_port;
union {
uint8_t ipv4[4];
uint8_t ipv6[16];
};
};
// Table 3. SDT symbolic parameters
static const float MAK_TIMEOUT_FACTOR = 0.1;
static const uint8_t MAK_MAX_RETRIES = 2; // (3 tries total)
static const uint8_t AD_HOC_TIMEOUT = 200; // ms
static const uint8_t AD_HOC_RETRIES = 2; // (3 tries total)
static const float RECIPROCAL_TIMEOUT_FACTOR = 0.2;
static const uint8_t MIN_EXPIRY_TIME = 2; // s
static const float NAK_TIMEOUT_FACTOR = 0.1;
static const uint8_t NAK_MAX_RETRIES = 2; // (3 tries total)
static const uint8_t NAK_HOLDOFF_INTERVAL = 2; // ms
static const uint8_t NAK_MAX_TIME = 10 * NAK_HOLDOFF_INTERVAL;
static const uint8_t NAK_BLANKTIME = 3 * NAK_HOLDOFF_INTERVAL;
static const uint16_t SDT_MULTICAST_PORT = 5568; // IANA registered “sdt”
} // UDP
} // SDT
} // ACN

View File

@ -1,111 +0,0 @@
/*
sdt.cpp
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "sdt.h"
namespace ACN {
namespace SDT {
/**
compare to another sessionID
*/
bool SessionId::operator== (const SessionId & other) const {
return ((other.cid == cid) &
(other.number == number) &
(other.protocol == protocol));
}
/**
Constuct a sequenced channel with an owner and a direction.
@param owner the owner of the channel
@param direction the direction of channel communication
*/
Channel::Channel(std::shared_ptr<Component> owner, Direction direction) {
owner_ = owner;
direction_ = direction;
}
/**
deconstructor that closes the channel cleanly.
*/
Channel::~Channel() {
// TODO: close the channel.
}
/**
Construct a new session.
*/
Session::Session() {
}
/**
deconstructor that leaves the session gracefully.
*/
Session::~Session() {
// TODO: Disconnect the session.
}
/**
get the ID of the session
*/
SessionId Session::id() {
SessionId ret;
ret.cid = leader->cid();
ret.number = number_;
ret.protocol = protocol_;
return ret;
}
Pdu::Pdu(PDU::Stream stream)
: PDU::Pdu(stream, 1) // vectors are 1 octet
{
// if (stream->fail()) return;
// if (!buffer_->good()) return;
}
client_pdu_header_t::client_pdu_header_t(PDU::Stream stream) {
protocol = stream->read32();
association = stream->read16();
}
ClientPdu::ClientPdu(PDU::Stream stream)
: PDU::Pdu(stream, 2) // vectors are 2 octets (MID)
{
if (stream->fail()) return;
if (!buffer_->good()) return;
if (flags_.hasHeader)
setHeader(new client_pdu_header_t(buffer_));
}
}; // SDT
}; // ACN

View File

@ -1,309 +0,0 @@
/*
sdt.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <list>
#include <memory>
#include <unordered_map>
#include "component.h"
#include "pdu.h"
#include "sdt-udp.h" // EPI 18
// ANSI E1.17- 2015, Architecture for Control Networks
// Session Data Transport Protocol
namespace ACN {
namespace SDT {
// 3.1 Session Identity
struct SessionId {
UUID::uuid cid; // the component ID (CID) of the session leader
uint16_t number; // the session number the leader has assigned
uint32_t protocol; // the ID of the protocol carried by the session
bool operator== (const SessionId &) const;
};
// 3.3 Sequenced Channels
// Sequenced channels transport three categories of traffic:
enum Direction {
internal, // SDT internal traffic
downstream, // Session downstream traffic
upstream // Session upstream traffic
};
// 3.5.1.1 Member Identifiers
using MID = uint16_t;
// 4.4.1.2 Channel Parameter Block
struct params_t {
uint8_t Expiry; // number of seconds without traffic before leaving
struct {
uint8_t NAK_Outbound : 1; // NAK to channel (1) or destination address (0)
uint8_t zero : 7;
};
uint16_t NAKholdoff; // calculation of a standoff time for sending NAKs
uint16_t NAKmodulus; // calculation of a standoff time for sending NAKs
uint16_t NAKmaxwait; // maximum milliseconds to wait before sending a NAK.
};
// 4.4.1 Join
struct join_data_t : PDU::pdu_data {
MID mid;
uint16_t number;
uint16_t reciprocal;
uint32_t sequence;
uint32_t reliable;
UDP::address_t destination;
params_t parameters;
uint32_t expiry;
};
// 4.4.2 Join Accept
struct join_accept_data_t : PDU::pdu_data {
UUID::uuid leader;
uint16_t number;
MID mid;
uint32_t reliable;
uint16_t reciprocal;
};
// 4.4.3 Join Refuse
struct join_refuse_data_t : PDU::pdu_data {
UUID::uuid leader;
uint16_t number;
MID mid;
uint32_t reliable;
uint8_t code;
};
// 4.4.4 Leaving
struct leaving_data_t : PDU::pdu_data {
UUID::uuid leader;
uint16_t number;
MID mid;
uint32_t reliable;
uint8_t code;
};
// 4.4.5 NAK
struct nak_data_t : PDU::pdu_data {
UUID::uuid leader;
uint16_t number;
MID mid;
uint32_t reliable;
uint32_t missed_first;
uint32_t missed_last;
};
// 4.4.6 Reliable Wrapper and Unreliable Wrapper
struct wrapper_data_t : PDU::pdu_data {
uint16_t number;
uint32_t sequence;
uint32_t reliable;
uint32_t oldest;
MID ack_range_begin;
MID ack_range_end;
uint16_t MAK_threshold;
// SDT client block
};
// 4.4.7 SDT Client Block
struct client_pdu_header_t : PDU::pdu_header {
uint32_t protocol;
uint16_t association;
client_pdu_header_t(PDU::Stream);
};
// Client Block PDU
class ClientPdu
: public PDU::Pdu
{
public:
ClientPdu(PDU::Stream);
};
// 4.4.8 Get Sessions
struct get_sessions_data_t : PDU::pdu_data {
UUID::uuid cid;
};
// 4.4.9.1 Channel Owner Info Block
struct channel_info_block_t {
MID mid;
UUID::uuid owner;
uint16_t number;
UDP::address_t destination;
UDP::address_t source;
uint16_t reciprocal;
uint16_t count;
std::list<uint32_t> protocols;
};
// 4.4.9 Sessions
struct sessions_data_t : PDU::pdu_data {
std::list<channel_info_block_t> list;
};
// 4.5.1 ACK
struct ack_data_t : PDU::pdu_data {
uint32_t reliable;
};
// 4.5.2 Channel Params
struct channel_params_data_t : PDU::pdu_data {
params_t parameters;
UDP::address_t address;
uint8_t expiry;
};
// 4.5.3 Connect
// 4.5.4 Connect Accept
// 4.5.6 Disconnect
struct connect_data_t : PDU::pdu_data {
uint32_t protocol;
};
// 4.5.5 Connect Refuse
// 4.5.7 Disconnecting
struct connect_refuse_data_t : PDU::pdu_data {
uint32_t protocol;
uint8_t code;
};
// 7.1 Protocol Code
static const uint32_t SDT_PROTOCOL_ID = 1; // PDU protocol value
// 7.2 PDU Vector Codes
enum sdt_vector_t {
REL_WRAP = 1,
UNREL_WRAP = 2,
CHANNEL_PARAMS = 3,
JOIN = 4,
JOIN_REFUSE = 5,
JOIN_ACCEPT = 6,
LEAVE = 7,
LEAVING = 8,
CONNECT = 9,
CONNECT_ACCEPT = 10,
CONNECT_REFUSE = 11,
DISCONNECT = 12,
DISCONNECTING = 13,
ACK = 14,
NAK = 15,
GET_SESSIONS = 16,
SESSIONS = 17,
};
// 7.4 Other Symbolic Parameters
// Table 6: Reason Codes
enum reason_code_t {
NONSPECIFIC = 1, // Non-specific, non-SDT reason.
ILLEGAL_PARAMETERS = 2, // Illegal channel parameters.
LOW_RESOURCES = 3, // Insufficient resources.
ALREADY_MEMBER = 4, // Multiple MIDs for single component.
BAD_ADDRESS_TYPE = 5, // Unrecognized transport address type.
NO_RECIPROCAL_CHANNEL = 6, // No upstream channel and cant create one
CHANNEL_EXPIRED = 7, // Channel has expired.
LOST_SEQUENCE = 8, // Unrecoverable packets missed.
SATURATED = 9, // Cant keep up, processor saturation.
TRANSPORT_ADDRESS_CHANGING = 10, // (e.g., IP number lease expired).
ASKED_TO_LEAVE = 11, // Asked to leave the channel.
NO_RECIPIENT = 12, // Component does not support protocol ID.
ONLY_UNICAST_SUPPORTED = 13 // Only unicast channels are supported
};
// Table 7: Address Specification Types
enum ip_addr_spec_t {
SDT_ADDR_NULL = 0, // Address is not present (0 octets).
SDT_ADDR_IPV4 = 1, // Address specified is in IP v4 format
SDT_ADDR_IPV6 = 2 // Address specified is in IP v6 format
};
// PDU type for this protocol
class Pdu
: public PDU::Pdu
{
public:
Pdu(PDU::Stream);
};
// Sequenced channels are unidirectional communication channels (unicast or
// multicast) from an owner component to one or more member components.
class Channel {
public:
Channel(std::shared_ptr<Component>, Direction);
~Channel();
private:
std::shared_ptr<Component> owner_;
Direction direction_ = internal;
};
// A session has a single leader and zero or more session members. The leader
// communicates to members using the downstream address. Members respond to the
// leader on the upstream address. A unique session identifier identifies a
// session.
class Session {
public:
Session();
~Session();
SessionId id();
// 4.4 SDT Base Layer Messages (non ad-hoc)
void join_accept() {};
void join_refuse() {};
void leaving() {};
void nak() {};
void reliable_wrapper() {};
void unreliable_wrapper() {};
// 4.5 SDT Wrapped Messages
void ack();
void channel_params();
void leave();
void connect();
void connect_accept();
void connect_refuse();
void disconnect();
void disconnecting();
protected:
std::shared_ptr<ACN::Component> leader;
std::shared_ptr<Channel> downstream;
std::unordered_map<MID, std::shared_ptr<Channel>> upstream;
private:
uint16_t number_;
uint32_t protocol_;
MID next_id_ = 1;
};
} // SDT
} // ACN

View File

@ -1,64 +0,0 @@
/*
universe.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "universe.h"
namespace DMX {
using std::copy;
/**
*/
Universe::Universe() {
null_start_data_.fill(0);
}
/**
accept new data from receiver
@param vector<uint8_t> varaibly sized data, beginning with a start code.
*/
void Universe::set(vector<uint8_t> vect) {
switch (vect.front()) { // start code
case E111_NULL_START:
vect.resize(null_start_data_.size(), 0); // pad shorter, truncate larger
copy(vect.begin(), vect.end(), null_start_data_.begin());
for (const auto &cb : callbacks_)
cb(this);
break;
default:
break;
}
}
/**
register a data consumer callback function
@param const DataHandlerFunction something that knows what to do with DMX
*/
void Universe::onData(const DataHandler callback)
{
callbacks_.push_back(callback);
}
} // DMX

View File

@ -1,72 +0,0 @@
/*
universe.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <functional>
#include <vector>
namespace DMX {
using std::uint8_t;
using std::uint16_t;
using std::array;
using std::function;
using std::vector;
// Table D1 - Reserved START Codes
static const uint8_t E111_NULL_START = 0;
static const uint8_t E111_ASC_TEXT_ASCII = 23;
static const uint8_t E111_ASC_TEST = 85;
static const uint8_t E111_ASC_TEXT_UTF8 = 144;
static const uint8_t E111_ASC_MANUFACTURER = 145;
static const uint8_t E111_ASC_SIP = 207;
class Universe; // forward declare the Univserse class
using DataHandler = function<void(Universe *)>;
using DimmerData = array<uint8_t, 513>;
/*
The Universe class
ANSI E1.11 describes may things about moving data over
serial EIA-485-A links. This class encapselates that data,
regardless of how it was transmitted.
*/
class Universe {
public:
Universe ();
DimmerData * data() { return &null_start_data_; }
void onData (const DataHandler callback);
void set (vector<uint8_t>);
uint8_t slot (uint16_t address) { return null_start_data_[address]; }
private:
DimmerData null_start_data_;
vector<DataHandler> callbacks_;
};
} // DMX

View File

@ -1,53 +0,0 @@
# Library for E1.31 sACN
## `Lightweight streaming protocol for transport of DMX512 using ACN`
## Top level include
Include `sacn.h` for full protocol support.
> ```#include "sacn.h"```
### Requirements
Expects the parent directory to contain the `acn` and `dmx` libraries.
## Logical components
### Protocol Handling
* `sacn.h`: [`SACN`] protocol constants.
* `data.h`: [`SACN::DATA`] protocol support for `VECTOR_ROOT_E131_DATA` packets.
* `extended.h`: [`SACN::EXTENDED`] protocol support for `VECTOR_ROOT_E131_EXTENDED` packets
### Data Classes
* `universe.h`: [`SACN::Universe`] A set of up to 512 data slots identified by universe number. Note: In E1.31 there may be multiple sources for a universe.
> For protocol agnostic universe refer to the base class, `DMX::Universe`
* `receiver.h`: [`SACN::Receiver`] A receiver is the intended target of information from a source. A receiver may listen on multiple universes.
* `receiver-esp.h`: [`SACN::EspReceiver`] A referance implimention, derived from `SACN::Receiver` for use with ESP devices and Arduino.
## Usage with Arduino
Include `receiver-esp.h` at the top of your sketch.
> ```
> #include "src/lib/sacn/receiver-esp.h"
> ```
Create a receiver object.
> ```
> EspReceiver * e131 = new EspReceiver();
> ```
In `setup`, subscribe to a universe an register a callback for data activity.
> ```
setup() {
e131->subscribe(1);
e131->universe(1)->onData(std::bind(&universeHandler,
std::placeholders::_1));
}
>```
Write a handler function with the follow signature (returns `void`, requires 1 argument, a `Universe` pointer):
> ```
void universeHandler(Universe * universe) {
do something...
}
> ```

View File

@ -1,52 +0,0 @@
/*
data.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "data.h"
namespace SACN {
namespace DATA {
frame_header::frame_header(PDU::Stream stream) {
stream->read(source_name, 64);
if (stream->gcount() != 64)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
priority = stream->read8();
sync_address = stream->read16();
sequence_number = stream->read8();
options = stream->read8();
universe = stream->read16();
}
Pdu::Pdu(PDU::Stream stream)
: PDU::Pdu(stream, 4) // vectors are 4 octets
{
if (stream->fail()) return;
if (!buffer_->good()) return;
if (flags_.hasHeader)
setHeader(new frame_header(buffer_));
}
} // DATA
} // SACN

View File

@ -1,60 +0,0 @@
/*
data.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "sacn.h"
namespace SACN {
namespace DATA {
using std::uint8_t;
using std::uint16_t;
// Table 6-1: E1.31 Data Packet Framing Layer
struct frame_header : PDU::pdu_header {
uint8_t source_name[64];
uint8_t priority;
uint16_t sync_address;
uint8_t sequence_number;
uint8_t options;
uint16_t universe;
frame_header(PDU::Stream);
};
// 6.2.6 E1.31 Data Packet: Options
enum options_t : uint8_t {
PREVIEW_DATA = 0b10000000, // Bit 7 = Preview_Data
STREAM_TERMINATED = 0b01000000, // Bit 6 = Stream_Terminated
FORCE_SYNCHRONIZATION = 0b00100000, // Bit 5 = Force_Synchronization
};
class Pdu
: public PDU::Pdu
{
public:
Pdu(PDU::Stream);
};
} // DATA
} // SACN

View File

@ -1,57 +0,0 @@
/*
extended.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "sacn.h"
namespace SACN {
using namespace ACN;
namespace EXTENDED {
using std::uint8_t;
using std::uint16_t;
// 6.3 E1.31 Synchronization Packet Framing Layer
struct frame_sync_header : PDU::pdu_header {
uint8_t sequence_number;
uint16_t sync_address;
uint8_t reserved[2];
};
// 6.4 E1.31 Universe Discovery Packet Framing Layer
struct frame_discovery_header : PDU::pdu_header {
uint8_t source_name[64];
uint8_t reserved[4];
};
// Table 8-9: E1.31 Universe Discovery Packet Universe Discovery Layer
struct discovery_list_header : PDU::pdu_header {
uint8_t page;
uint8_t last_page;
};
} // EXTENDED
} // SACN

View File

@ -1,70 +0,0 @@
/*
receiver-esp.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "receiver-esp.h"
// ESP logging module
#include <Arduino.h>
#include <esp_log.h>
static const char* TAG = "EspReceiver";
namespace SACN {
EspReceiver::EspReceiver(UUID::uuid cid)
: Receiver(cid)
{
udp.onPacket(std::bind(&EspReceiver::UdpStreamHandler, this,
std::placeholders::_1));
}
void EspReceiver::subscribe(const uint16_t num) {
if (universe(num)) // already subscribed
return;
ESP_LOGI(TAG, "Subscribing to universe # %d", num);
Receiver::subscribe(num);
// listen multicast; works for unicast too
udp.listenMulticast(IPv4MulticastAddress(num),
ACN_SDT_MULTICAST_PORT);
}
void EspReceiver::unsubscribe(const uint16_t num) {
if (!universe(num)) // not subscribed
return;
ESP_LOGI(TAG, "Unubscribing from universe # %d", num);
Receiver::unsubscribe(num);
// AsyncUDP has no way to unsubscribe IGMP?
}
void EspReceiver::UdpStreamHandler(AsyncUDPPacket udp_packet) {
// Expecting IANA registered Session Data Transport traffic
if (!udp_packet.localPort() == ACN_SDT_MULTICAST_PORT)
return;
// wrap a PDU io stream around the AsyncUDPPacket data buffer
PDU::Stream stream(new PDU::pdu_stream(udp_packet.data(),
udp_packet.available()));
Appliance::UdpStreamHandler(stream);
}
} // SACN

View File

@ -1,66 +0,0 @@
/*
receiver-esp.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <Arduino.h>
#include <IPAddress.h>
#include <IPv6Address.h>
#include <AsyncUDP.h>
#include "receiver.h"
#include "../dmx/universe.h"
/*
Arduino specification additions to the sACN library
*/
namespace SACN {
// 9.3.1 Allocation of IPv4 Multicast Addresses
// Multicast addresses are from the IPv4 Local Scope.
inline IPAddress IPv4MulticastAddress(uint16_t universe) {
return IPAddress(239, 255, (universe >> 8), (universe & 0xff));
};
// 9.3.2 Allocation of IPv6 Multicast Addresses
inline IPv6Address IPv6MulticastAddress(uint16_t universe) {
IPv6Address address;
address.fromString("ff18::83:00:" +
String(universe >> 8, HEX) + ":" +
String(universe & 0xff, HEX));
return address;
};
class EspReceiver
: public SACN::Receiver
{
public:
EspReceiver(UUID::uuid = UUID::uuid());
virtual void subscribe(const uint16_t universe = 1);
virtual void unsubscribe(const uint16_t);
private:
AsyncUDP udp; // AsyncUDP
void UdpStreamHandler(AsyncUDPPacket); // UDP packet parser callback
};
} // SACN

View File

@ -1,178 +0,0 @@
/*
receiver.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "receiver.h"
#include "data.h"
namespace SACN {
/**
Constructor. Register RLP vector callbacks.
*/
Receiver::Receiver(UUID::uuid cid)
: Appliance(cid)
{
registerRlpVectorHandler(VECTOR_ROOT_E131_DATA,
std::bind(&Receiver::rootDataHandler, this, std::placeholders::_1));
registerRlpVectorHandler(VECTOR_ROOT_E131_EXTENDED,
std::bind(&Receiver::rootExtendedHandler, this, std::placeholders::_1));
}
void Receiver::subscribe(const uint16_t num) {
if (!universes_.count(num))
universes_.emplace(num, new SACN::Universe());
}
void Receiver::unsubscribe(const uint16_t num) {
if (universes_.count(num))
universes_.erase(num);
}
SACN::Universe * Receiver::universe(uint16_t universe) {
if (universes_.count(universe))
return universes_.at(universe);
return 0;
}
/**
Receive VECTOR_ROOT_E131_DATA vector'd packets.
@param pdu is a shared pointer to the PDU
*/
void Receiver::rootDataHandler(std::shared_ptr<RLP::Pdu> root) {
auto block = PDU::readBlock<DATA::Pdu>(root->buffer(), root);
if (root->buffer()->fail())
return;
for(auto frame : *block) {
// 6.2.1 E1.31 Data Packet: Vector
// Sources sending an E1.31 Data Packet shall set the E1.31 Layer's Vector
// to VECTOR_E131_DATA_PACKET. This value indicates that the E1.31 framing
// layer is wrapping a DMP PDU.
switch(frame->vector()) {
case VECTOR_E131_DATA_PACKET:
dataPacketHandler(frame);
break;
default:
break;
}
}
}
/**
Receive `VECTOR_ROOT_E131_DATA -> VECTOR_E131_DATA_PACKET` vector'd packets.
Merging will be based on frame header. PDU data will be read as a block of DMP PDUs and passed to the universe.
@param pdu is a shared pointer to the PDU
*/
void Receiver::dataPacketHandler(std::shared_ptr<DATA::Pdu> frame) {
// header may be inherited. check that one exists
if (!frame->header())
return;
auto source = std::shared_ptr<UniverseSource>(new UniverseSource(frame));
if (universes_.count(source->universe()) == 0)
return;
Universe * universe = universes_.at(source->universe());
// 6.2.3 E1.31 Data Packet: Priority
// No priority outside the range of 0 to 200 shall be transmitted on
// the network.
if (source->priority() > 200)
frame->buffer()->setstate(frame->buffer()->rdstate() |
std::ios_base::failbit);
// 6.2.6 E1.31 Data Packet: Options
// Preview_Data: Bit 7 (most significant bit)
// This bit, when set to 1, indicates that the data in this packet is intended for use in visualization or media server preview applications and shall not be used to generate live output.
if (source->isPreview())
return;
// 6.2.6 E1.31 Data Packet: Options
// Stream_Terminated: Bit 6
// allow E1.31 sources to terminate transmission of a stream or of
// universe synchronization without waiting for a timeout to occur.
// Any property values in an E1.31 Data Packet containing this bit
// shall be ignored.
if (source->isTerminated()) {
unsubscribe(source->universe());
return;
}
// 6.2.6 E1.31 Data Packet: Options
// Force_Synchronization: Bit 5
// This bit indicates whether to lock or revert to an unsynchronized state
// when synchronization is lost. When set to 0, components that had been
// operating in a synchronized state shall not update with any new packets
// until synchronization resumes. When set to 1, once synchronization has
// been lost, components that had been operating in a synchronized state need
// not wait for a new E1.31 Synchronization Packet in order to update to the
// next E1.31 Data Packet.
if (!source->isForced() &&
universe->isSyncronized()) {
return; // operate in synchronized state?
}
// 6.2.4.1 Synchronization Address Usage in an E1.31 Data Packet
// a value of 0 in the Synchronization Address indicates that the universe
// data is not synchronized.
if (source->syncAddress() != 0) {
// TODO: do somthing to engage synchronization
}
// If a receiver is presented with an E1.31 Data Packet containing a Synchronization Address of 0, it shall discard any data waiting to be processed and immediately act on that Data Packet.
if (source->syncAddress() == 0 && universe->isSyncronized()) {
// 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::readBlock<DMP::Pdu>(frame->buffer(), frame);
if (frame->buffer()->fail())
return;
for (auto dmp : *block) {
// 7.2 DMP Layer: Vector
// The DMP Layer's Vector shall be set to VECTOR_DMP_SET_PROPERTY, which
// indicates a DMP Set Property message by sources. Receivers shall discard
// the packet if the received value is not VECTOR_DMP_SET_PROPERTY.
switch(dmp->vector()) {
case DMP::SET_PROPERTY:
universe->set(dmp, source);
break;
default:
break;
}
}
}
}; // SACN

View File

@ -1,54 +0,0 @@
/*
receiver.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "data.h"
#include "sacn.h"
#include "universe.h"
#include <unordered_map>
namespace SACN {
class Receiver
: public Appliance
{
public:
Receiver(UUID::uuid = UUID::uuid());
virtual void subscribe(const uint16_t);
virtual void unsubscribe(const uint16_t);
SACN::Universe * universe(uint16_t universe);
protected:
// process data frames
void rootDataHandler(std::shared_ptr<RLP::Pdu>);
void dataPacketHandler(std::shared_ptr<DATA::Pdu>);
// process extended frames
void rootExtendedHandler(std::shared_ptr<RLP::Pdu>) {};
private:
std::unordered_map <uint16_t, SACN::Universe *> universes_;
};
};

View File

@ -1,55 +0,0 @@
/*
sacn.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include "../acn/acn.h"
// E1.31 Lightweight streaming protocol for transport of DMX512 using ACN
namespace SACN {
using namespace ACN;
using std::uint8_t;
using std::uint16_t;
using std::uint32_t;
// Appendix A: Defined Parameters (Normative)
static const uint32_t VECTOR_ROOT_E131_DATA = 0x00000004;
static const uint32_t VECTOR_ROOT_E131_EXTENDED = 0x00000008;
static const uint8_t VECTOR_DMP_SET_PROPERTY = 0x02;
static const uint32_t VECTOR_E131_DATA_PACKET = 0x00000002;
static const uint32_t VECTOR_E131_EXTENDED_SYNCHRONIZATION = 0x00000001;
static const uint32_t VECTOR_E131_EXTENDED_DISCOVERY = 0x00000002;
static const uint32_t VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST = 0x00000001;
static const uint16_t E131_E131_UNIVERSE_DISCOVER_INTERVAL = 10000; // ms
static const uint16_t E131_NETWORK_DATA_LOSS_TIMEOUT = 2500; // ms
static const uint16_t E131_DISCOVERY_UNIVERSE = 64214;
static const uint16_t ACN_SDT_MULTICAST_PORT = 5568;
} // SACN

View File

@ -1,105 +0,0 @@
/*
universe.cpp
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "universe.h"
namespace SACN {
/**
Construct a Universe Source from an sACN frame PDU
*/
UniverseSource::UniverseSource(std::shared_ptr<DATA::Pdu> pdu) {
auto root_header = (RLP::rlp_header*)pdu->parent()->header();
cid_ = root_header->cid;
auto frame_header = (DATA::frame_header*)pdu->header();
description_ = std::string((char*)frame_header->source_name);
universe_ = frame_header->universe;
priority_ = frame_header->priority;
sync_address_ = frame_header->sync_address;
options_ = frame_header->options;
};
/**
Construct a new Universe.
*/
Universe::Universe()
: DMX::Universe()
{
synchronized_ = false;
}
/**
Set universe data from a DMP PDU from a UniverseSource.
*/
void Universe::set(std::shared_ptr<DMP::Pdu> dmp,
std::shared_ptr<UniverseSource> source) {
// 7.3 Address Type and Data Type
// Sources shall set the DMP Layer's Address Type and Data Type to 0xa1.
// 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 (!type->z_reserved) return; // needs to be true, but why?
if (type->relative) return;
if (type->type != ACN::DMP::ARRAY) return;
if (type->x_reserved != 0) return;
if (type->width != ACN::DMP::TWO) return;
// 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
// 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)
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)
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)
return;
// 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::set(pd);
source_ = source;
}
}; // SACN

View File

@ -1,82 +0,0 @@
/*
universe.h
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "sacn.h"
#include "data.h"
#include "../dmx/universe.h"
#include "../uuid/uuid.h"
#include <memory>
#include <string>
namespace SACN {
/**
universe metadata
*/
class UniverseSource
{
public:
UniverseSource(std::shared_ptr<DATA::Pdu>);
const UUID::uuid cid() const {return cid_;};
const std::string description() const {return description_;}
const uint16_t universe() const {return universe_;}
const uint8_t priority() const {return priority_;}
const uint16_t syncAddress() const {return sync_address_;}
const bool isTerminated() const {return options_
& DATA::STREAM_TERMINATED;}
const bool isPreview() const {return options_
& DATA::PREVIEW_DATA;}
const bool isForced() const {return options_
& DATA::FORCE_SYNCHRONIZATION;}
private:
UUID::uuid cid_;
std::string description_;
uint16_t universe_;
uint8_t priority_;
uint16_t sync_address_;
uint8_t options_;
};
/**
universe data
*/
class Universe
: public DMX::Universe
{
public:
Universe();
bool isSyncronized() const {return synchronized_;};
void set(std::shared_ptr<DMP::Pdu>, std::shared_ptr<UniverseSource>);
private:
bool synchronized_;
std::shared_ptr<UniverseSource> source_;
};
};

View File

@ -1,259 +0,0 @@
/*
uuid.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "uuid.h"
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <iomanip>
#include <ctime>
namespace UUID {
/**
construct a NIL UUID
*/
uuid::uuid() {
type_ = NIL;
version_ = VOID;
timestamp_ = 0;
clock_seq_ = 0;
node_ = 0;
setBytes();
}
/**
create this UUID from a byte array
*/
void uuid::fromArray(const uint8_t * bytes) {
std::memcpy(raw_, bytes, sizeof(raw_));
setType();
if (type_ != RFC4122) return;
setVersion();
setFields();
}
/**
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
*/
void uuid::fromString(std::string str) {
// remove dashes
str.erase(std::remove(str.begin(), str.end(), '-'), str.end());
if (str.length() != 32) return;
// fill buffer
uint8_t buf[16];
for (unsigned int i = 0; i < sizeof(buf); i++)
buf[i] = std::strtoul(str.substr((i*2), 2).c_str(), NULL, 16);
// process buffer
fromArray(buf);
};
/*
output this UUID as a hex string
*/
std::string uuid::hex() const {
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(2);
for (uint8_t raw : raw_)
oss << raw;
return oss.str();
}
/**
output this UUID as formated hex string
*/
std::string uuid::string() const {
std::string str = hex();
str.reserve(str.length() + 4);
for (int idx : {8, 13, 18, 23})
str.insert(idx, "-");
return str;
};
/**
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
*/
// TODO: Check endianness
void uuid::setBytes() {
if (type_ == NIL)
std::memset(raw_, 0, sizeof(raw_));
if (type_ != RFC4122) return;
Fields 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.node_low = node_;
fields.node_high = node_ >> 16;
std::memcpy(raw_, &fields, sizeof(raw_));
// version
raw_[7] = (raw_[7] & 0x0f) | (version_ << 4);
// type
raw_[8] = (raw_[8] & 0b00111111) | (type_ << 6);
}
/**
populate data fields from byte array
*/
// TODO: Check endianness
void uuid::setFields() {
Fields fields;
std::memcpy(&fields, raw_, sizeof(raw_));
timestamp_ = fields.time_low;
timestamp_ |= (uint64_t)fields.time_mid << 32;
timestamp_ |= (uint64_t)(fields.time_hi_version & 0x0fff) << 48;
clock_seq_ = fields.clock_seq_low;
clock_seq_ |= (fields.clock_seq_hi_variant & 0b00111111) << 8;
node_ = fields.node_low;
node_ |= (fields.node_high << 16);
}
/**
exctract the type from the raw bytes
*/
void uuid::setType() {
if ((raw_[8] >> 7) == 0b0) {
type_ = NCS;
} else if ((raw_[8] >> 6) == 0b10) {
type_ = RFC4122;
} else if ((raw_[8] >> 5) == 0b110) {
type_ = MS;
} else {
type_ = RESVERED;
}
}
/**
exctract the version from the raw bytes
*/
void uuid::setVersion() {
switch (raw_[7] >> 4) {
case TIME:
version_ = TIME;
break;
case DCE:
version_ = DCE;
break;
case MD5:
version_ = MD5;
break;
case RAND:
version_ = RAND;
break;
case SHA1:
version_ = SHA1;
break;
default:
version_ = VOID;
}
}
/**
compare to another UUID
*/
bool uuid::operator== (const uuid & other) const {
return std::memcmp(raw_, other.bytes(), sizeof(raw_));
}
/**
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_));
}
/**
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
*/
void uuid::uuid4() {
type_ = RFC4122;
version_ = RAND;
std::srand(std::time(nullptr));
timestamp_ = std::rand();
timestamp_ |= (uint64_t)std::rand() << 32;
clock_seq_ = std::rand();
node_ = std::rand();
node_ |= (uint64_t)std::rand() << 32;
setBytes();
}
// const std::string NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
// const std::string NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
// const std::string NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
// const std::string NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";
}; // UUID

View File

@ -1,128 +0,0 @@
/*
uuid.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
#include <cstring>
#include <string>
// RFC4122 A Universally Unique IDentifier (UUID) URN Namespace
namespace UUID {
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 Version {
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 Fields {
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 uint8_t * raw) : uuid() { fromArray(raw); };
uuid(const char * cstr) : uuid() { fromCstring(cstr); };
uuid(std::string str) : uuid() { fromString(str); };
// accessors
const Type type() const { return type_; };
const Version 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_; };
// comparitor overload
bool operator== (const uuid &) const;
bool operator== (const uint8_t *) const;
bool operator== (const char *) const;
bool operator== (const std::string &) const;
// typecast overload
operator const uint8_t * () const { return raw_; };
operator const std::string () const { return string(); };
// output
std::string hex() const; // '12345678123456781234567812345678'
std::string string() const;// '12345678-1234-5678-1234-567812345678'
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 uuid4(); // very low quality of random
virtual void uuid5(Namespace, std::string) {};
private:
uint8_t raw_[16];
Type type_;
Version version_;
uint64_t timestamp_ : 60;
uint16_t clock_seq_ : 14;
uint64_t node_ : 48;
void fromArray(const uint8_t *);
void fromCstring(const char *);
void fromString(std::string);
void setBytes();
void setType();
void setVersion();
void setFields();
}; // 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