remove libESTA as directory, now a submodule
This commit is contained in:
parent
d1fcb08bd8
commit
e3f3fa5b45
|
@ -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 | |
|
|
@ -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`]
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 property’s value may not be read.
|
||||
NOT_WRITABLE = 4, // The property’s 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 property’s 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 can’t create one
|
||||
CHANNEL_EXPIRED = 7, // Channel has expired.
|
||||
LOST_SEQUENCE = 8, // Unrecoverable packets missed.
|
||||
SATURATED = 9, // Can’t 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
|
|
@ -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
|
|
@ -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
|
|
@ -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...
|
||||
}
|
||||
> ```
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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_;
|
||||
};
|
||||
|
||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
};
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue