156 lines
4.3 KiB
C++
156 lines
4.3 KiB
C++
/*
|
|
universesender.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 "universesender.h"
|
|
#include "universe.h"
|
|
|
|
namespace sACN {
|
|
|
|
/**
|
|
* @brief UniverseSender::UniverseSender
|
|
* @param universe
|
|
*/
|
|
UniverseSender::UniverseSender(Universe * universe)
|
|
: mUniverse(universe)
|
|
, terminated_resend(3)
|
|
, minimum_update_time(22700)
|
|
, last_null_data({0})
|
|
, retransmission_count(0)
|
|
, keep_alive_interval(800)
|
|
, enable_(true)
|
|
, worker_(&UniverseSender::loop_, this)
|
|
{
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief UniverseSender::~UniverseSender
|
|
*/
|
|
UniverseSender::~UniverseSender()
|
|
{
|
|
if (isSending())
|
|
{
|
|
kill();
|
|
worker_.join();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief UniverseSender::isSending
|
|
* @return
|
|
*/
|
|
bool UniverseSender::isSending()
|
|
{
|
|
return (worker_.joinable());
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief UniverseSender::flush
|
|
*/
|
|
void UniverseSender::flush()
|
|
{
|
|
request_.notify_all();
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief UniverseSender::kill
|
|
*/
|
|
void UniverseSender::kill()
|
|
{
|
|
control_mutex_.lock();
|
|
enable_ = false;
|
|
control_mutex_.unlock();
|
|
flush();
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief UniverseSender::loop_
|
|
*/
|
|
void UniverseSender::loop_()
|
|
{
|
|
bool enabled = true; // at least 1 loop
|
|
bool new_data;
|
|
std::chrono::nanoseconds elapsed;
|
|
std::chrono::microseconds sleep;
|
|
std::mutex mtx; // std::conditional_variable requires in the sleeping thread. Why??
|
|
|
|
while (enabled || terminated_resend > 0)
|
|
{
|
|
// enforce strict minimum update times
|
|
elapsed = std::chrono::system_clock::now() - mUniverse->last_updated_;
|
|
if (elapsed < minimum_update_time)
|
|
std::this_thread::sleep_for(minimum_update_time - elapsed);
|
|
|
|
// check for control permission to continue looping
|
|
control_mutex_.lock();
|
|
enabled = enable_;
|
|
control_mutex_.unlock();
|
|
|
|
if (enable_)
|
|
{
|
|
mUniverse->setStatus(Universe::DMX_ACTIVE);
|
|
mUniverse->null_start_mutex.lock();
|
|
new_data = (mUniverse->null_start_data != last_null_data);
|
|
if (new_data)
|
|
{
|
|
last_null_data = mUniverse->null_start_data;
|
|
retransmission_count = 0;
|
|
}
|
|
mUniverse->null_start_mutex.unlock();
|
|
if (++retransmission_count > 3)
|
|
{
|
|
retransmission_count = 3; // prevent counter from overflowing
|
|
sleep = keep_alive_interval;
|
|
}
|
|
else
|
|
sleep = minimum_update_time;
|
|
}
|
|
else
|
|
{
|
|
mUniverse->setStatus(Universe::sACN_TERMINATED); // note the changed operating status
|
|
mUniverse->metadata_->options.stream_terminated = true; // set the stream_terminated bit
|
|
--terminated_resend; // stream_terminated must be sent 3 times
|
|
sleep = minimum_update_time; // stay throttled up through the termination sequence
|
|
}
|
|
|
|
// send the sACN message
|
|
mUniverse->sendDMP(mUniverse->as_DMP_());
|
|
mUniverse->last_updated_ = std::chrono::system_clock::now();
|
|
/// > \cite sACN 6.2.5 E1.31 Data Packet: Sequence Number
|
|
/// >
|
|
/// > ... The sequence number for a universe shall be incremented by one for
|
|
/// > every packet sent on that universe...
|
|
mUniverse->metadata_->sequence_number++;
|
|
|
|
// sleep before the next cycle
|
|
request_.wait_for(mtx, sleep);
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace sACN
|