You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

527 lines
18 KiB
C++

// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*!
* @file Publisher.cxx
* This file contains the implementation of the publisher functions.
*
* This file was generated by the tool fastddsgen.
*/
#include "Publisher.hpp"
#include <condition_variable>
#include <csignal>
#include <stdexcept>
#include <thread>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/log/Log.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
#include <fastdds/dds/publisher/qos/PublisherQos.hpp>
#include "SystemPubSubTypes.hpp"
#include "json.hpp"
#include "msg.hpp"
#include "DEBUG.hpp"
using namespace eprosima::fastdds::dds;
using json = nlohmann::json;
PublisherApp::PublisherApp(
const int& domain_id)
: factory_(nullptr)
, participant_(nullptr)
, publisher_(nullptr)
, bar_topic_(nullptr)
, bar_writer_(nullptr)
, bar_type_(new WeighingSystem::BarCommandUpdatePubSubType())
, light_topic_(nullptr)
, light_writer_(nullptr)
, light_type_(new WeighingSystem::LightsCommandUpdatePubSubType())
, print_topic_(nullptr)
, print_writer_(nullptr)
, print_type_(new InternalSystem::PrintReqPubSubType())
, matched_(0)
, samples_sent_(0)
, stop_(false)
{
//
// Create the participant
DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT;
pqos.name("Core_pub_participant");
pqos.wire_protocol().builtin.discovery_config.leaseDuration = Duration_t(60, 0);
pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(30, 0);
factory_ = DomainParticipantFactory::get_shared_instance();
participant_ = factory_->create_participant(domain_id, pqos, nullptr, StatusMask::none());
if (participant_ == nullptr)
{
throw std::runtime_error("Core Participant initialization failed");
}
// Register the type
bar_type_.register_type(participant_);
light_type_.register_type(participant_);
print_type_.register_type(participant_);
// Create the publisher
PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT;
participant_->get_default_publisher_qos(pub_qos);
publisher_ = participant_->create_publisher(pub_qos, nullptr, StatusMask::none());
if (publisher_ == nullptr)
{
throw std::runtime_error("Core Publisher initialization failed");
}
// Create the topic
TopicQos topic_qos = TOPIC_QOS_DEFAULT;
participant_->get_default_topic_qos(topic_qos);
bar_topic_ = participant_->create_topic("BarCommandUpdate", bar_type_.get_type_name(), topic_qos);
if (bar_topic_ == nullptr)
{
throw std::runtime_error("BarCommandUpdate Topic initialization failed");
}
// Create the data writer
DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT;
publisher_->get_default_datawriter_qos(writer_qos);
writer_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
writer_qos.reliability().max_blocking_time = Duration_t(1, 0);
writer_qos.durability().kind = DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS;
writer_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
writer_qos.history().depth = 1;
writer_qos.resource_limits().max_samples = 200;
writer_qos.resource_limits().max_instances = 1;
writer_qos.resource_limits().max_samples_per_instance = 100;
writer_qos.data_sharing().off();
bar_writer_ = publisher_->create_datawriter(bar_topic_, writer_qos, this, StatusMask::all());
if (bar_writer_ == nullptr)
{
throw std::runtime_error("WeighingSystem::BarUpdate DataWriter initialization failed");
}
// Create the topic
topic_qos = TOPIC_QOS_DEFAULT;
participant_->get_default_topic_qos(topic_qos);
light_topic_ = participant_->create_topic("LightsCommandUpdate", light_type_.get_type_name(), topic_qos);
if (light_topic_ == nullptr)
{
throw std::runtime_error("LightsCommandUpdate Topic initialization failed");
}
// Create the data writer
writer_qos = DATAWRITER_QOS_DEFAULT;
publisher_->get_default_datawriter_qos(writer_qos);
writer_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
writer_qos.reliability().max_blocking_time = Duration_t(1, 0);
writer_qos.durability().kind = DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS;
writer_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
writer_qos.history().depth = 1;
writer_qos.resource_limits().max_samples = 200;
writer_qos.resource_limits().max_instances = 1;
writer_qos.resource_limits().max_samples_per_instance = 100;
writer_qos.data_sharing().off();
light_writer_ = publisher_->create_datawriter(light_topic_, writer_qos, this, StatusMask::all());
if (light_writer_ == nullptr)
{
throw std::runtime_error("WeighingSystem::LightsUpdate DataWriter initialization failed");
}
// Create the topic
topic_qos = TOPIC_QOS_DEFAULT;
participant_->get_default_topic_qos(topic_qos);
print_topic_ = participant_->create_topic("PrintReq", print_type_.get_type_name(), topic_qos);
if (print_topic_ == nullptr)
{
throw std::runtime_error("PrintReq Topic initialization failed");
}
// Create the data writer
writer_qos = DATAWRITER_QOS_DEFAULT;
publisher_->get_default_datawriter_qos(writer_qos);
writer_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
writer_qos.reliability().max_blocking_time = Duration_t(1, 0);
writer_qos.durability().kind = DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS;
writer_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
writer_qos.history().depth = 1;
writer_qos.resource_limits().max_samples = 200;
writer_qos.resource_limits().max_instances = 1;
writer_qos.resource_limits().max_samples_per_instance = 100;
writer_qos.data_sharing().off();
print_writer_ = publisher_->create_datawriter(print_topic_, writer_qos, this, StatusMask::all());
if (print_writer_ == nullptr)
{
throw std::runtime_error("InternalSystem::PrintReq DataWriter initialization failed");
}
}
PublisherApp::~PublisherApp()
{
if (nullptr != participant_)
{
// Delete DDS entities contained within the DomainParticipant
participant_->delete_contained_entities();
// Delete DomainParticipant
factory_->delete_participant(participant_);
}
}
void PublisherApp::on_publication_matched(
DataWriter* writer,
const PublicationMatchedStatus& info)
{
if (info.current_count_change == 1)
{
{
std::lock_guard<std::mutex> lock(mutex_);
matched_ = info.current_count;
}
DEBUG(writer->get_topic()->get_name() << " Publisher matched.");
cv_.notify_one();
}
else if (info.current_count_change == -1)
{
{
std::lock_guard<std::mutex> lock(mutex_);
matched_ = info.current_count;
}
DEBUG(writer->get_topic()->get_name() << " Publisher unmatched.");
}
else
{
DEBUG(info.current_count_change << " is not a valid value for PublicationMatchedStatus current count change");
}
}
bool PublisherApp::bar_ctrl(const std::map<std::string, std::string>& ctrl)
{
WeighingSystem::BarCommandUpdate cmd;
for (const auto &[port, opt] : ctrl)
{
if (port == "FrontBar")
{
if (opt == "up")
{
cmd.FrontBarSignalUp() = 1;
cmd.FrontBarSignalDown() = 0;
}
else
{
cmd.FrontBarSignalUp() = 0;
cmd.FrontBarSignalDown() = 1;
}
cmd.FrontBarEnable() = 1;
}
else if (port == "BackBar")
{
if (opt == "up")
{
cmd.BackBarSignalUp() = 1;
cmd.BackBarSignalDown() = 0;
}
else
{
cmd.BackBarSignalUp() = 0;
cmd.BackBarSignalDown() = 1;
}
cmd.BackBarEnable() = 1;
}
}
DEBUG("send bar ctrl cmd");
bar_writer_->write(&cmd);
return true;
}
bool PublisherApp::light_ctrl(const std::map<std::string, std::string>& ctrl)
{
WeighingSystem::LightsCommandUpdate cmd;
for (const auto &[port, opt] : ctrl)
{
if (port == "FrontLED")
{
if (opt == "red")
{
cmd.FrontLEDSignal() = 1;
}
else
{
cmd.FrontLEDSignal() = 2;
}
cmd.FrontLEDEnable() = 1;
}
else if (port == "BackLED")
{
if (opt == "red")
{
cmd.BackLEDSignal() = 1;
}
else
{
cmd.BackLEDSignal() = 2;
}
cmd.BackLEDEnable() = 1;
}
}
DEBUG("send light ctrl cmd");
light_writer_->write(&cmd);
return true;
}
bool PublisherApp::print_receipt(const std::map<std::string, std::string>& msg)
{
InternalSystem::PrintReq req;
req.msg() = msg;
for (auto &m : req.msg())
{
DEBUG("first: " << m.first << " second: " << m.second);
}
print_writer_->write(&req);
return true;
}
extern std::string mqtt_topic_id;
void PublisherApp::run(std::shared_ptr<mqtt::async_client> dev)
{
while (!is_stopped())
{
//dds msg
std::unique_lock<std::mutex> dds_lock(DdsMsgData::queue_cv_mtx_, std::try_to_lock);
if (dds_lock.owns_lock())
{
if (!DdsMsgData::LicenseSnapUpdate_queue_.empty())
{
WeighingSystem::LicenseSnapUpdate info = std::move(DdsMsgData::LicenseSnapUpdate_queue_.front());
DdsMsgData::LicenseSnapUpdate_queue_.pop();
dds_lock.unlock();
// DEBUG("车牌: " << info.License());
// DEBUG("类型: " << info.NewTag());
if (dev != nullptr)
{
if (dev->is_connected())
{
std::string payload = "{\"value\": \"" + info.License() + "\"}";
auto mqtt_msg = mqtt::make_message("pound/" + std::string(mqtt_topic_id) + "/licensesnap/license", payload);
mqtt_msg->set_qos(0);
mqtt_msg->set_retained(true);
dev->publish(mqtt_msg);
}
}
}
else if (!DdsMsgData::ScaleInfo_queue_.empty())
{
WeighingSystem::ScaleInfo info = std::move(DdsMsgData::ScaleInfo_queue_.front());
DdsMsgData::ScaleInfo_queue_.pop();
dds_lock.unlock();
// DEBUG("有车: " << info.HasVehicle());
// DEBUG("稳定: " << info.WeightOK());
// DEBUG("设备状态: " << info.State());
// DEBUG("实时重量: " << info.Value());
// DEBUG("稳定重量: " << info.StableValue());
if (dev != nullptr)
{
if (dev->is_connected())
{
std::string payload = "{\"value\": " + std::to_string(info.Value()) + "}";
auto mqtt_msg = mqtt::make_message("pound/" + std::string(mqtt_topic_id) + "/scale/weight", payload);
mqtt_msg->set_qos(0);
mqtt_msg->set_retained(true);
dev->publish(mqtt_msg);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
payload = "{\"value\": " + std::to_string(info.StableValue()) + "}";
mqtt_msg = mqtt::make_message("pound/" + std::string(mqtt_topic_id) + "/scale/stableweight", payload);
mqtt_msg->set_qos(0);
mqtt_msg->set_retained(true);
dev->publish(mqtt_msg);
}
}
}
else if (!DdsMsgData::BarUpdate_queue_.empty())
{
WeighingSystem::BarUpdate info = std::move(DdsMsgData::BarUpdate_queue_.front());
DdsMsgData::BarUpdate_queue_.pop();
dds_lock.unlock();
if (dev != nullptr)
{
if (dev->is_connected())
{
std::string payload = "{\"value\": " + std::to_string(info.FrontBarState()) + "}";
auto mqtt_msg = mqtt::make_message("pound/" + std::string(mqtt_topic_id) +"/barrier/frontstatus", payload);
mqtt_msg->set_qos(0);
mqtt_msg->set_retained(true);
dev->publish(mqtt_msg);
}
}
}
else if (!DdsMsgData::LightsUpdate_queue_.empty())
{
WeighingSystem::LightsUpdate info = std::move(DdsMsgData::LightsUpdate_queue_.front());
DdsMsgData::LightsUpdate_queue_.pop();
dds_lock.unlock();
if (dev != nullptr)
{
if (dev->is_connected())
{
std::string payload = "{\"value\": " + std::to_string(info.FrontLEDState()) + "}";
auto mqtt_msg = mqtt::make_message("pound/" + std::string(mqtt_topic_id) +"/light/frontstatus ", payload);
mqtt_msg->set_qos(0);
mqtt_msg->set_retained(true);
dev->publish(mqtt_msg);
}
}
}
else if (!DdsMsgData::InfraredUpdate_queue_.empty())
{
WeighingSystem::InfraredUpdate info = std::move(DdsMsgData::InfraredUpdate_queue_.front());
DdsMsgData::InfraredUpdate_queue_.pop();
dds_lock.unlock();
if (dev != nullptr)
{
if (dev->is_connected())
{
std::string payload = "{\"value\": " + std::to_string(info.FrontResistanceSignal()) + "}";
auto mqtt_msg = mqtt::make_message("pound/" + std::string(mqtt_topic_id) +"/infrared/frontvalue", payload);
mqtt_msg->set_qos(0);
mqtt_msg->set_retained(true);
dev->publish(mqtt_msg);
}
}
}
else
{
dds_lock.unlock();
}
}
// mqtt msg
std::unique_lock<std::mutex> mqtt_lock(MqttMsgData::queue_cv_mtx_, std::try_to_lock);
if (mqtt_lock.owns_lock())
{
if (!MqttMsgData::Mqtt_msg_queue_.empty())
{
mqtt::const_message_ptr msg = std::move(MqttMsgData::Mqtt_msg_queue_.front());
MqttMsgData::Mqtt_msg_queue_.pop();
mqtt_lock.unlock();
std::string topic = msg->get_topic();
std::string payload = msg->to_string();
json cmd = json::parse(payload);
if (topic.find("barrier/frontup") != std::string::npos)
{
if (cmd["value"] == 1)
{
std::map<std::string, std::string> ctrl;
ctrl["FrontBar"] = "up";
bar_ctrl(ctrl);
}
}
else if (topic.find("barrier/frontdown") != std::string::npos)
{
if (cmd["value"] == 1)
{
std::map<std::string, std::string> ctrl;
ctrl["FrontBar"] = "down";
bar_ctrl(ctrl);
}
}
else if (topic.find("light/frontsignal") != std::string::npos)
{
if (cmd["value"] == 1)
{
std::map<std::string, std::string> ctrl;
ctrl["FrontLED"] = "red";
light_ctrl(ctrl);
}
else
{
std::map<std::string, std::string> ctrl;
ctrl["FrontLED"] = "green";
light_ctrl(ctrl);
}
}
}
else
{
mqtt_lock.unlock();
}
}
// Wait for period or stop event
std::unique_lock<std::mutex> period_lock(mutex_);
cv_.wait_for(period_lock, std::chrono::milliseconds(period_ms_), [this]()
{
return is_stopped();
});
}
}
bool PublisherApp::publish()
{
bool ret = false;
// Wait for the data endpoints discovery
std::unique_lock<std::mutex> matched_lock(mutex_);
cv_.wait(matched_lock, [&]()
{
// at least one has been discovered
return ((matched_ > 0) || is_stopped());
});
if (!is_stopped())
{
/* Initialize your structure here */
WeighingSystem::BarCommandUpdate sample_;
ret = (RETCODE_OK == bar_writer_->write(&sample_));
}
return ret;
}
bool PublisherApp::is_stopped()
{
return stop_.load();
}
void PublisherApp::stop()
{
stop_.store(true);
cv_.notify_one();
}