1
0
Fork 0

worker thread for streaming sACN

This commit is contained in:
Kevin Matz 2021-09-01 12:53:53 -04:00
parent b3256be388
commit 5c0cc41af5
3 changed files with 120 additions and 7 deletions

View File

@ -43,7 +43,7 @@ may not be inherited from sibling `PDU` in the data.
| :- | :-: | :-: |
| 0 to 10 V Analog Control | E1.3 | |
| USITT DMX512-A | E1.11 | Data Abstraction |
| ACN Root Layer Protocol (RLP) | E1.17 | Rx |
| ACN Root Layer Protocol (RLP) | E1.17 | |
| ACN Session Data Transport Protocol (SDT) | E1.17 | |
| ACN Device Management Protocol (DMP) | E1.17 | Limited |
| ACN Device Description Language (DDL) | E1.17 | |
@ -53,9 +53,9 @@ may not be inherited from sibling `PDU` in the data.
| 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 17 - ACN Root Layer Protocol Operation on UDP | E1.17 | |
| EPI 18 - Operation of SDT on UDP Networks | E1.17 | |
| EPI 19 - ACN Discovery on IP Networks | E1.17 | |
| EPI 19 - ACN Discovery on IP Networks | E1.17 | Names |
| 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 | Responder |
@ -68,12 +68,12 @@ may not be inherited from sibling `PDU` in the data.
| 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 | Partial |
| EPI 33 - ACN RLP Operation on TCP | E1.30-11 | |
| Streaming ACN (sACN) | E1.31 | Data/Discovery |
| sACN Receiver | E1.31 | ✓ |
| sACN Source | E1.31 | Limited |
| sACN Source | E1.31 | |
| sACN Data | E1.31 | ✓ |
| sACN Sync | E1.31 | |
| sACN Sync | E1.31 | Rx |
| sACN Discovery | E1.31 | ✓ |
| sACN Preview | E1.31 | - |
| RDMNet | E1.33 | |

View File

@ -36,6 +36,7 @@ Universe::Universe(Source* src)
, active_data_slots(0)
, provenance_(std::make_shared<DATA::data_header>())
, source_(src)
, tx_worker_(&Universe::tx_loop_, this)
{
destination.type = ACN::SDT::SDT_ADDR_NULL;
}
@ -46,6 +47,17 @@ Universe::Universe(Source* src)
*/
Universe::~Universe()
{
// shut down tx worker thread
if (tx_worker_.joinable())
{
tx_control_mutex_.lock();
tx_enable_ = false;
tx_control_mutex_.unlock();
tx_request_.notify_all();
tx_worker_.join();
}
// delete sync data pointer
delete sync_data_;
}
@ -169,6 +181,9 @@ void Universe::setValue (const uint16_t address, const uint8_t value)
// set the value
DMX::Universe::setValue(address, value);
// request sACN message to be sent
tx_request_.notify_all();
}
@ -196,6 +211,9 @@ void Universe::setValue (const uint16_t start, const uint16_t footprint,
// set the values
DMX::Universe::setValue(start, footprint, data);
// request sACN message to be sent
tx_request_.notify_all();
}
@ -304,4 +322,91 @@ void Universe::sACNsend() const
}
}
/**
* @brief Universe::tx_loop_
*/
void Universe::tx_loop_()
{
// rx universes, by definition, won't have a source set
if (!source_)
return;
// run at least 1 loop
bool enable = true;
/// > \cite sACN 6.6.1 Transmission Rate
/// >
/// > E1.31 sources shall not transmit packets for a given universe number
/// > at a rate which exceeds the maximum refresh rate specified in
/// > E1.11 \cite DMX
///
/// > \cite DMX Table 6 - Timing Diagram Values - output of transmitting UART
/// >
/// > Minimum Update Time for 513 slots : 22.7ms
std::chrono::milliseconds minimum_update_time(23);
/// > \cite sACN 6.6.2 Null START Code Transmission Requirements in E1.31
/// > Data Packets
/// >
/// > 1. Three packets containing the non-changing Property Values
/// > (corresponding to DMX512-A slot data) shall be sent before the
/// > initiation of transmission suppression.
DMX::DimmerData last_null_data({0});
uint retransmission_count = 0;
/// > 2. Thereafter, a single keep-alive packet shall be transmitted at
/// > intervals of between 800mS and 1000mS.
std::chrono::milliseconds keep_alive_interval(800);
std::chrono::system_clock::time_point last_sent;
// I don't fully understand the semantics of std::conditional_variable,
// but it requires this mutex in the sleeping thread.
std::mutex mtx;
while (enable)
{
// enforce strict minimum update times
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now() - last_sent);
if (elapsed < minimum_update_time)
std::this_thread::sleep_for(minimum_update_time - elapsed);
// check for control permission to continue looping
tx_control_mutex_.lock();
enable = tx_enable_;
tx_control_mutex_.unlock();
// if shutting down, send stream_terminated in this last update
if (!enable)
provenance_->options.stream_terminated = true;
// see if this is new data or re-transmitting
auto sleep = std::chrono::milliseconds(minimum_update_time);
null_start_mutex.lock();
if (null_start_data != last_null_data)
{
retransmission_count = 0;
last_null_data = null_start_data;
}
else
if (++retransmission_count >= 2)
sleep = std::chrono::milliseconds(keep_alive_interval);
null_start_mutex.unlock();
// send the sACN message
sACNsend();
last_sent = std::chrono::system_clock::now();
// sleep before the next cycle
if (enable)
{
mtx.lock();
tx_request_.wait_for(mtx, sleep);
mtx.unlock();
}
}
}
}; // namespace SACN

View File

@ -28,7 +28,9 @@
#include "dmx/universe.h"
#include <cstdint>
#include <condition_variable>
#include <memory>
#include <thread>
#include <vector>
namespace sACN {
@ -97,6 +99,12 @@ private:
/// > between the sequence number of an E1.31 Synchronization Packet and
/// > the sequence number of an E1.31 Data Packet on that same universe.
uint8_t sync_sequence_ = 0;
std::condition_variable_any tx_request_;
std::mutex tx_control_mutex_;
bool tx_enable_ = true;
std::thread tx_worker_;
void tx_loop_();
};
} // SACN namespace