// 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" // // 【新增】红外对射状态打印函数 // #include // void print_infrared_status() // { // while (!DdsMsgData::stop_flag_) // { // { // std::lock_guard lock(DdsMsgData::infrared_mtx_); // std::cout << "[红外对射状态] Front: " // << DdsMsgData::latest_infrared_.FrontResistanceSignal() // << " Back: " // << DdsMsgData::latest_infrared_.BackResistanceSignal() // << std::endl; // } // std::this_thread::sleep_for(std::chrono::seconds(2)); // } // } 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_LIC 1 #define WEIGH_STABLE1 2 //#define WEIGH_STABLE2 3 //#define WEIGH_SEND 4 //#define WEIGH_PRINT 5 //#define WEIGH_ERROR 6 #define WEIGH_LEAVE 3 #define WEIGH_STABLE_WAIT 4 void PublisherApp::run() { std::string license_no; float stable_weight = 0; float stable_weight1 = 0; //float stable_weight2 = 0; int weigh_state = WEIGH_IDLE; std::chrono::steady_clock::time_point stable_start_time; bool stable_timer_running = false; // 稳定计时是否在跑 float stable_weight_at_wait = 0; // 记录进入WEIGH_STABLE_WAIT时的稳定重量 // 【新增】启动红外对射状态打印线程 //std::thread infrared_thread(print_infrared_status); while (!is_stopped()) { // 【调试】每 20 帧打印一次状态机关键变量 static int dbg_cnt = 0; if (++dbg_cnt % 20 == 0) { DEBUG("[HEARTBEAT] state=" << weigh_state << " lic=[" << license_no << "]" << " sw=" << stable_weight << " sw1=" << stable_weight1 << " tr=" << stable_timer_running); } std::unique_lock 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 (license_no.empty() == true) if (true) // 收到车牌识别就触发,不做条件判断 { license_no = info.License(); weigh_state = WEIGH_LIC; // 识别到车牌,抬起前拦车器 std::map ctrl; ctrl["FrontBar"] = "up"; bar_ctrl(ctrl); } } 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 (info.WeightOK() == true) { stable_weight = info.StableValue(); } // else // { // stable_weight = 0; // } // if (info.HasVehicle() == 0) // { // license_no.clear(); // if (weigh_state == WEIGH_LEAVE) // { // std::this_thread::sleep_for(std::chrono::seconds(5)); // std::map ctrl; // ctrl["FrontBar"] = "down"; // bar_ctrl(ctrl); // weigh_state = WEIGH_IDLE; // } // } if (info.HasVehicle() == 0) { // else if (license_no.empty() != true) // { // license_no.clear(); // } } } else if (!DdsMsgData::BarUpdate_queue_.empty()) { WeighingSystem::BarUpdate info = std::move(DdsMsgData::BarUpdate_queue_.front()); DdsMsgData::BarUpdate_queue_.pop(); dds_lock.unlock(); DEBUG("前拦车器状态: " << info.FrontBarState()); DEBUG("后拦车器状态: " << info.BackBarState()); } else if (!DdsMsgData::LightsUpdate_queue_.empty()) { WeighingSystem::LightsUpdate info = std::move(DdsMsgData::LightsUpdate_queue_.front()); DdsMsgData::LightsUpdate_queue_.pop(); dds_lock.unlock(); DEBUG("前红绿灯状态: " << info.FrontLEDState()); DEBUG("后红绿灯状态: " << info.BackLEDState()); } else if (!DdsMsgData::InfraredUpdate_queue_.empty()) { WeighingSystem::InfraredUpdate info = std::move(DdsMsgData::InfraredUpdate_queue_.front()); DdsMsgData::InfraredUpdate_queue_.pop(); dds_lock.unlock(); DEBUG("前红外对射状态: " << info.FrontResistanceSignal()); DEBUG("后红外对射状态: " << info.BackResistanceSignal()); } else if (!DdsMsgData::WeightInfoOk_queue_.empty()) { WeighingSystem::WeightInfoOk info = std::move(DdsMsgData::WeightInfoOk_queue_.front()); DdsMsgData::WeightInfoOk_queue_.pop(); dds_lock.unlock(); auto formatFloat = [](float value) -> std::string { std::ostringstream oss; oss << std::fixed << std::setprecision(2) << value; return oss.str(); }; DEBUG("==== WeightInfoOk 接收 ===="); DEBUG(" IsPrintTicker = " << info.IsPrintTicker()); DEBUG(" GrossDeviceID = " << info.GrossDeviceID()); DEBUG(" GrossDeviceName = " << info.GrossDeviceName()); DEBUG(" TareDeviceID = " << info.TareDeviceID()); DEBUG(" TareDeviceName = " << info.TareDeviceName()); DEBUG(" EnterpriseName = " << info.EnterpriseName()); DEBUG(" BillNumber = " << info.BillNumber()); DEBUG(" CarNumber = " << info.CarNumber()); DEBUG(" Supplier = " << info.Supplier()); DEBUG(" GoodsType = " << info.GoodsType()); DEBUG(" GrossWeight = " << info.GrossWeight()); DEBUG(" GrossTime = " << info.GrossTime()); DEBUG(" GrossOperater = " << info.GrossOperater()); DEBUG(" Tare = " << info.Tare()); DEBUG(" TareTime = " << info.TareTime()); DEBUG(" TareOperater = " << info.TareOperater()); DEBUG(" Suttle = " << info.Suttle()); DEBUG(" duduction1 = " << info.duduction1()); DEBUG(" duduction2 = " << info.duduction2()); DEBUG(" duduction3 = " << info.duduction3()); DEBUG(" INCoalYard = " << info.INCoalYard()); DEBUG(" OutCoalYard = " << info.OutCoalYard()); DEBUG(" BatchNumber = " << info.BatchNumber()); DEBUG(" Warning = " << info.Warning()); DEBUG(" Tips = " << info.Tips()); DEBUG(" TicketType = " << info.TicketType()); DEBUG("============================"); if (info.IsPrintTicker() == true) { std::map print_msg; print_msg["Title"] = "贵州渝黔锰业有限公司提货单"; print_msg["GrossDeviceID"] = std::to_string(info.GrossDeviceID()); print_msg["GrossDeviceName"] = info.GrossDeviceName(); print_msg["TareDeviceID"] = std::to_string(info.TareDeviceID()); print_msg["TareDeviceName"] = info.TareDeviceName(); print_msg["TitleCorp"] = info.EnterpriseName(); print_msg["CoalNumber"] = info.BillNumber(); print_msg["CarNumber"] = info.CarNumber(); print_msg["Supplier"] = info.Supplier(); print_msg["GoodsType"] = info.GoodsType(); print_msg["GrossWeight"] = formatFloat(info.GrossWeight()); print_msg["GrossTime"] = info.GrossTime(); print_msg["GrossOperater"] = info.GrossOperater(); print_msg["TareWeight"] = formatFloat(info.Tare()); print_msg["TareTime"] = info.TareTime(); print_msg["TareOperater"] = info.TareOperater(); print_msg["SuttleWeight"] = formatFloat(info.Suttle()); print_msg["duduction1"] = formatFloat(info.duduction1()); print_msg["duduction2"] = formatFloat(info.duduction2()); print_msg["duduction3"] = formatFloat(info.duduction3()); print_msg["INCoalYard"] = info.INCoalYard(); print_msg["OUTCoalYard"] = info.OutCoalYard(); print_msg["BatchNumber"] = info.BatchNumber(); print_msg["Warning"] = info.Warning(); print_msg["Tips"] = info.Tips(); print_msg["TicketType"] = info.TicketType(); print_msg["OrderNumber"] = info.OrderNumber(); print_msg["TrainNumber"] = info.VehicleAndVesselNumber(); print_msg["Customer"] = info.ReceiveCompany(); print_msg["Transporter"] = info.TransportCompany(); print_receipt(print_msg); std::this_thread::sleep_for(std::chrono::seconds(1)); } weigh_state = WEIGH_LEAVE; std::map ctrl; ctrl["FrontBar"] = "up"; bar_ctrl(ctrl); } // else if (!DdsMsgData::WeightInfoError_queue_.empty()) // { // WeighingSystem::WeightInfoError info = std::move(DdsMsgData::WeightInfoError_queue_.front()); // DdsMsgData::WeightInfoError_queue_.pop(); // dds_lock.unlock(); // weigh_state = WEIGH_ERROR; // } else { dds_lock.unlock(); } } // logic // switch (weigh_state) // { // case WEIGH_IDLE: // break; // case WEIGH_LIC: // if ((stable_weight != 0) && (license_no.empty() != true)) // { // DEBUG("stable_weight1 " << stable_weight); // DEBUG("license_no " << license_no); // stable_weight1 = stable_weight; // weigh_state = WEIGH_STABLE1; // } // break; // case WEIGH_STABLE1: // if (stable_weight == 0) // { // DEBUG("weigh1 clear"); // weigh_state = WEIGH_STABLE2; // } // break; // case WEIGH_STABLE2: // if ((stable_weight != 0) && (license_no.empty() != true)) // { // DEBUG("license_no " << license_no); // DEBUG("stable_weight2 " << stable_weight); // stable_weight2 = stable_weight; // if ((stable_weight1 - stable_weight2) > 45) // { // weigh_state = WEIGH_SEND; // } // else // { // DEBUG("stable_weight2 error"); // stable_weight1 = stable_weight; // weigh_state = WEIGH_STABLE1; // } // } // break; // case WEIGH_SEND: // DEBUG("send summary"); // { // WeighingSystem::SummaryUpdate info; // info.License() = license_no; // info.StableValue() = stable_weight2; // summary_writer_->write(&info); // } // weigh_state = WEIGH_PRINT; // break; // case WEIGH_PRINT: // break; // case WEIGH_ERROR: // std::this_thread::sleep_for(std::chrono::seconds(3)); // weigh_state = WEIGH_STABLE2; // break; // case WEIGH_LEAVE: // break; // default: // weigh_state = WEIGH_IDLE; // break; // } switch (weigh_state) { case WEIGH_IDLE: break; case WEIGH_LIC: DEBUG("[STATE] WEIGH_LIC sw=" << stable_weight << " lic=[" << license_no << "]"); if ((stable_weight != 0) && (license_no.empty() != true)) { DEBUG("stable_weight1 " << stable_weight); DEBUG("license_no " << license_no); stable_weight1 = stable_weight; weigh_state = WEIGH_STABLE1; } break; case WEIGH_STABLE1: if (stable_weight == 0) { DEBUG("weigh1 clear, wait for card..."); // 重量归零,重置计时器 stable_timer_running = false; } else { // 读取前红外对射状态 long front_ir = 0; { std::lock_guard lock(DdsMsgData::infrared_mtx_); front_ir = DdsMsgData::latest_infrared_.FrontResistanceSignal(); } if (front_ir != 0) // 红外被遮挡(==1),关闭计时器 { stable_timer_running = false; DEBUG("Front infrared blocked (sig=" << front_ir << "), timer closed."); } else // 红外无遮挡(==0),启动/继续计时 { if (!stable_timer_running) { stable_start_time = std::chrono::steady_clock::now(); stable_timer_running = true; DEBUG("Infrared clear, starting 10s timer..."); } auto now = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast(now - stable_start_time).count(); } } break; case WEIGH_STABLE_WAIT: // 第一次进入时记录当前重量为基准 if (stable_weight_at_wait == 0) { stable_weight_at_wait = stable_weight; } // 等待司机下车刷卡,通过重量变化 > 30KG 检测司机下车 if (stable_weight > 0 && stable_weight_at_wait > 0) { float weight_diff = std::abs(stable_weight - stable_weight_at_wait); if (weight_diff > 30) { DEBUG("Weight changed by " << weight_diff << " kg, driver may have left, waiting for card..."); stable_weight_at_wait = stable_weight; // 更新基准重量 } } else if (stable_weight == 0) { DEBUG("Scale is empty, waiting for card..."); stable_weight_at_wait = 0; } break; case WEIGH_LEAVE: break; default: weigh_state = WEIGH_IDLE; break; } // Wait for period or stop event std::unique_lock period_lock(mutex_); cv_.wait_for(period_lock, std::chrono::milliseconds(period_ms_), [this]() { return is_stopped(); }); } // // 【新增】停止红外打印线程 // DdsMsgData::stop_flag_ = true; // infrared_thread.join(); } 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(); }