// 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 #include #include #include #include #include #include // 新增:用于 std::fabs #include #include #include #include #include #include #include "WeighingDDSTypePubSubTypes.hpp" #include "msg.hpp" #include "DEBUG.hpp" using namespace eprosima::fastdds::dds; 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()) , summary_topic_(nullptr) , summary_writer_(nullptr) , summary_type_(new WeighingSystem::SummaryUpdatePubSubType()) , print_topic_(nullptr) , print_writer_(nullptr) , print_type_(new WeighingSystem::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_); summary_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); summary_topic_ = participant_->create_topic("SummaryUpdate", summary_type_.get_type_name(), topic_qos); if (summary_topic_ == nullptr) { throw std::runtime_error("SummaryUpdate 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(); summary_writer_ = publisher_->create_datawriter(summary_topic_, writer_qos, this, StatusMask::all()); if (summary_writer_ == nullptr) { throw std::runtime_error("WeighingSystem::SummaryUpdate 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 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 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& 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& 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& msg) { WeighingSystem::PrintReq req; req.msg() = msg; for (auto &m : req.msg()) { DEBUG("first: " << m.first << " second: " << m.second); } print_writer_->write(&req); return true; } #define WEIGH_IDLE 0 #define WEIGH_QUEUE_RAISED 1 // 已抬杆,计时等 60s 落杆 void PublisherApp::run() { int weigh_state = WEIGH_IDLE; while (!is_stopped()) { // 1) 消费 DDS 队列 std::unique_lock dds_lock(DdsMsgData::queue_cv_mtx_, std::try_to_lock); if (dds_lock.owns_lock()) { if (!DdsMsgData::QueueSuccess_queue_.empty()) { Queue::QueueSuccess info = std::move(DdsMsgData::QueueSuccess_queue_.front()); DdsMsgData::QueueSuccess_queue_.pop(); dds_lock.unlock(); DEBUG("==== QueueSuccess received, raising front bar ===="); DEBUG(" message_id = " << info.message_id()); DEBUG(" card_number = " << info.card_number()); DEBUG(" device_id = " << info.device_id()); // 抬前拦车器 std::map ctrl; ctrl["FrontBar"] = "up"; bar_ctrl(ctrl); // 抬后拦车器 // std::map ctrl; // ctrl["BackBar"] = "up"; // bar_ctrl(ctrl); // 收到 QueueSuccess 后下发"排队票"打印任务(仅打一次) // 字段映射:QueueSuccess → Print1_3 期望的 map key { std::map print_msg; print_msg["Title"] = "排队票"; // 触发 print/MsgHandler2.cxx::Print1_3 print_msg["CarNumber"] = info.vehicle_number(); // 车牌号 print_msg["DateTime"] = info.queue_time(); // 时间 print_msg["QueueID"] = std::to_string(info.queue_number()); // 排队号 (long→string) print_msg["Supplier"] = std::to_string(info.sample_code()); // 采样编码 print_msg["GoodsType"] = info.goods_name(); // 品种 print_msg["sample_machine"] = info.sample_machine(); // 采样机名称 print_msg["CoalYard"] = ""; // 煤场:缺省为空(冒号后无内容) print_receipt(print_msg); } // 记录抬杆时刻,开始 60s 倒计时 queue_success_time_ = std::chrono::steady_clock::now(); queue_success_pending_ = true; weigh_state = WEIGH_QUEUE_RAISED; } else { dds_lock.unlock(); } } // 2) 状态机 switch (weigh_state) { case WEIGH_IDLE: break; case WEIGH_QUEUE_RAISED: if (queue_success_pending_) { auto elapsed = std::chrono::duration_cast( std::chrono::steady_clock::now() - queue_success_time_).count(); if (elapsed >= 60) { DEBUG("60s elapsed after QueueSuccess, lowering front bar..."); std::map ctrl; ctrl["FrontBar"] = "down"; bar_ctrl(ctrl); // std::map ctrl; // ctrl["BackBar"] = "down"; // bar_ctrl(ctrl); queue_success_pending_ = false; weigh_state = WEIGH_IDLE; } } break; default: weigh_state = WEIGH_IDLE; break; } // 3) 周期等待 std::unique_lock 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 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(); }