Apollo 9.0
自动驾驶开放平台
hmi_worker.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <cstdio>
20#include <utility>
21
22#include "absl/strings/str_cat.h"
23#include "absl/strings/str_join.h"
24#include "absl/strings/str_split.h"
25
26#include "cyber/proto/dag_conf.pb.h"
27#include "cyber/proto/record.pb.h"
28#include "modules/dreamview/proto/scenario.pb.h"
30#include "cyber/common/file.h"
46
47DEFINE_string(cyber_recorder_play_command, "cyber_recorder play -p 1 -f ",
48 "Cyber recorder play command");
49
50namespace apollo {
51namespace dreamview {
52namespace {
53
68using apollo::monitor::ComponentStatus;
69using apollo::monitor::SystemStatus;
70using RLock = boost::shared_lock<boost::shared_mutex>;
71using WLock = boost::unique_lock<boost::shared_mutex>;
72using Json = nlohmann::json;
73
74constexpr char kNavigationModeName[] = "Navigation";
75// operations based on sim control is enabled, note that it is
76// consistent with the field name in hmistatus
77const std::vector<HMIModeOperation> OperationBasedOnSimControl = {
78 HMIModeOperation::Scenario_Sim,
79 HMIModeOperation::Sim_Control,
80};
81
82template <class FlagType, class ValueType>
83void SetGlobalFlag(std::string_view flag_name, const ValueType &value,
84 FlagType *flag) {
85 constexpr char kGlobalFlagfile[] =
86 "/apollo/modules/common/data/global_flagfile.txt";
87 if (*flag != value) {
88 *flag = value;
89 // Overwrite global flagfile.
90 std::ofstream fout(kGlobalFlagfile, std::ios_base::app);
91 ACHECK(fout) << "Fail to open global flagfile " << kGlobalFlagfile;
92 fout << "\n--" << flag_name << "=" << value << std::endl;
93 }
94}
95
96void System(std::string_view cmd) {
97 const int ret = std::system(cmd.data());
98 if (ret == 0) {
99 AINFO << "SUCCESS: " << cmd;
100 } else {
101 AERROR << "FAILED(" << ret << "): " << cmd;
102 }
103}
104
105} // namespace
106
108 const std::shared_ptr<Node> &node,
109 const apollo::common::monitor::MonitorLogBuffer& monitor_log_buffer)
110 : config_(util::HMIUtil::LoadConfig(FLAGS_dv_plus_hmi_modes_config_path)),
111 node_(node),
112 monitor_log_buffer_(monitor_log_buffer) {
113 InitStatus();
114 LoadDvPluginPanelsJson();
115 time_interval_ms_ = 3000;
116 overtime_time_ = 3;
117 monitor_timer_.reset(new cyber::Timer(
118 time_interval_ms_, [this]() { this->OnTimer(overtime_time_); }, false));
119 monitor_timer_->Start();
120}
121
122void HMIWorker::Start(DvCallback callback_api) {
123 callback_api_ = callback_api;
124 InitReadersAndWriters();
125 RegisterStatusUpdateHandler(
126 [this](const bool status_changed, HMIStatus *status) {
127 apollo::common::util::FillHeader("HMI", status);
128 status_writer_->Write(*status);
129 status->clear_header();
130 });
131 ResetComponentStatusTimer();
132 thread_future_ = cyber::Async(&HMIWorker::StatusUpdateThreadLoop, this);
133}
134
135void HMIWorker::Stop() {
136 stop_ = true;
137 std::system(FLAGS_terminal_stop_cmd.data());
138 if (thread_future_.valid()) {
139 thread_future_.get();
140 }
141}
142
143bool HMIWorker::LoadVehicleDefinedMode(const std::string &mode_config_path,
144 const std::string &current_vehicle_path,
145 HMIMode *self_defined_mode) {
146 const std::string mode_file_name =
147 cyber::common::GetFileName(mode_config_path);
148 const std::string vehicle_mode_config_path =
149 current_vehicle_path + "/dreamview_conf/hmi_modes/" + mode_file_name;
150 if (!cyber::common::PathExists(vehicle_mode_config_path)) {
151 return false;
152 }
153 ACHECK(cyber::common::GetProtoFromFile(vehicle_mode_config_path,
154 self_defined_mode))
155 << "Unable to parse vehicle self defined HMIMode from file "
156 << vehicle_mode_config_path;
157 util::HMIUtil::TranslateCyberModules(self_defined_mode);
158 return true;
159}
160
161void HMIWorker::InitStatus() {
162 static constexpr char kDockerImageEnv[] = "DOCKER_IMG";
163 status_.set_docker_image(cyber::common::GetEnv(kDockerImageEnv));
164 status_.set_utm_zone_id(FLAGS_local_utm_zone_id);
165
166 // Populate modes and current_mode.
167 const auto &modes = config_.modes();
168 for (const auto &iter : modes) {
169 const std::string &mode = iter.first;
170 status_.add_modes(mode);
171 if (mode == FLAGS_vehicle_calibration_mode) {
172 FuelMonitorManager::Instance()->RegisterFuelMonitor(
173 mode, std::make_unique<DataCollectionMonitor>());
174 FuelMonitorManager::Instance()->RegisterFuelMonitor(
175 mode, std::make_unique<PreprocessMonitor>());
176 } else if (mode == FLAGS_lidar_calibration_mode) {
177 FuelMonitorManager::Instance()->RegisterFuelMonitor(
178 mode, std::make_unique<PreprocessMonitor>("lidar_to_gnss"));
179 } else if (mode == FLAGS_camera_calibration_mode) {
180 FuelMonitorManager::Instance()->RegisterFuelMonitor(
181 mode, std::make_unique<PreprocessMonitor>("camera_to_lidar"));
182 }
183 }
184
185 // Populate maps and current_map.
186 for (const auto &map_entry : config_.maps()) {
187 status_.add_maps(map_entry.first);
188
189 // If current FLAG_map_dir is available, set it as current_map.
190 if (map_entry.second == FLAGS_map_dir) {
191 status_.set_current_map(map_entry.first);
192 }
193 }
194
195 // Populate vehicles and current_vehicle.
196 for (const auto &vehicle : config_.vehicles()) {
197 status_.add_vehicles(vehicle.first);
198 }
199
200 // Initial HMIMode by priority:
201 // 1. NavigationMode if --use_navigation_mode is specified explicitly.
202 // 2. CachedMode if it's stored in KV database.
203 // 3. default_hmi_mode if it is available.
204 // 4. Pick the first available mode.
205 const std::string cached_mode =
206 KVDB::Get(FLAGS_current_mode_db_key).value_or("");
207 if (FLAGS_use_navigation_mode && ContainsKey(modes, kNavigationModeName)) {
208 ChangeMode(kNavigationModeName);
209 } else if (ContainsKey(modes, cached_mode)) {
210 ChangeMode(cached_mode);
211 } else if (ContainsKey(modes, FLAGS_default_hmi_mode)) {
212 ChangeMode(FLAGS_default_hmi_mode);
213 } else {
214 ChangeMode(modes.begin()->first);
215 }
216}
217
218void HMIWorker::InitReadersAndWriters() {
219 status_writer_ = node_->CreateWriter<HMIStatus>(FLAGS_hmi_status_topic);
220 action_command_client_ = node_->CreateClient<ActionCommand, CommandStatus>(
221 FLAGS_action_command_topic);
222 audio_event_writer_ =
223 node_->CreateWriter<AudioEvent>(FLAGS_audio_event_topic);
224 drive_event_writer_ =
225 node_->CreateWriter<DriveEvent>(FLAGS_drive_event_topic);
226
227 monitor_reader_ = node_->CreateReader<SystemStatus>(
228 FLAGS_system_status_topic,
229 [this](const std::shared_ptr<SystemStatus> &system_status) {
230 this->ResetComponentStatusTimer();
231
232 WLock wlock(status_mutex_);
233
234 const bool is_realtime_msg =
235 FLAGS_use_sim_time
236 ? system_status->is_realtime_in_simulation()
238 system_status->header().timestamp_sec() <
239 FLAGS_system_status_lifetime_seconds;
240 // Update modules running status from realtime SystemStatus.
241 if (is_realtime_msg) {
242 for (auto &iter : *status_.mutable_modules()) {
243 bool previous_second = iter.second;
244 auto *status = FindOrNull(system_status->hmi_modules(), iter.first);
245 iter.second =
246 status != nullptr && status->status() == ComponentStatus::OK;
247 if (previous_second != iter.second) {
248 LockModule(iter.first, false);
249 }
250 }
251 // system_status is true, indicating that the monitor immediately
252 // detected the module startup status
253 if (system_status->detect_immediately()) {
254 status_.set_expected_modules(status_.expected_modules() - 1);
255 }
256 }
257 // Update monitored components status.
258 for (auto &iter : *status_.mutable_monitored_components()) {
259 auto *status = FindOrNull(system_status->components(), iter.first);
260 if (status != nullptr) {
261 iter.second = status->summary();
262 } else {
263 iter.second.set_status(ComponentStatus::UNKNOWN);
264 iter.second.set_message("Status not reported by Monitor.");
265 }
266 }
267
268 // Update other components status.
269 for (auto &iter : *status_.mutable_other_components()) {
270 auto *status =
271 FindOrNull(system_status->other_components(), iter.first);
272 if (status != nullptr) {
273 iter.second.CopyFrom(*status);
274 } else {
275 iter.second.set_status(ComponentStatus::UNKNOWN);
276 iter.second.set_message("Status not reported by Monitor.");
277 }
278 }
279 // For global components.
280 for (auto &iter : *system_status->mutable_global_components()) {
281 (*status_.mutable_global_components())[iter.first] = iter.second;
282 }
283
284 // Check if the status is changed.
285 const size_t new_fingerprint =
287 if (last_status_fingerprint_ != new_fingerprint) {
288 status_changed_ = true;
289 last_status_fingerprint_ = new_fingerprint;
290 }
291 });
292
293 node_->CreateReader<RecordInfo>(
294 FLAGS_record_info_topic,
295 [this](const std::shared_ptr<RecordInfo> &record_info) {
296 WLock wlock(status_mutex_);
297 if (record_info->record_name() ==
298 status_.current_record_status().current_record_id()) {
299 status_.mutable_current_record_status()->set_curr_time_s(
300 record_info.get()->curr_time_s());
301 status_changed_ = true;
302 }
303 });
304
305 localization_reader_ =
306 node_->CreateReader<LocalizationEstimate>(FLAGS_localization_topic);
307 // Received Chassis, trigger action if there is high beam signal.
308 chassis_reader_ = node_->CreateReader<Chassis>(
309 FLAGS_chassis_topic, [this](const std::shared_ptr<Chassis> &chassis) {
310 if (Clock::NowInSeconds() - chassis->header().timestamp_sec() <
311 FLAGS_system_status_lifetime_seconds) {
312 if (chassis->signal().high_beam()) {
313 // Currently we do nothing on high_beam signal.
314 const bool ret = Trigger(HMIAction::NONE);
315 AERROR_IF(!ret) << "Failed to execute high_beam action.";
316 }
317 }
318 });
319}
320
321bool HMIWorker::Trigger(const HMIAction action) {
322 AERROR << "HMIAction " << HMIAction_Name(action) << " was triggered!";
323 switch (action) {
324 case HMIAction::NONE:
325 break;
326 case HMIAction::SETUP_MODE:
327 SetupMode();
328 AddExpectedModules(action);
329 break;
330 case HMIAction::ENTER_AUTO_MODE:
331 return ChangeDrivingMode(Chassis::COMPLETE_AUTO_DRIVE);
332 case HMIAction::DISENGAGE:
333 return ChangeDrivingMode(Chassis::COMPLETE_MANUAL);
334 case HMIAction::RESET_MODE:
335 ResetMode();
336 break;
337 case HMIAction::LOAD_DYNAMIC_MODELS:
338 LoadDynamicModels();
339 break;
340 case HMIAction::LOAD_RECORDS:
341 LoadRecords();
342 break;
343 case HMIAction::LOAD_RTK_RECORDS:
344 LoadRtkRecords();
345 break;
346 case HMIAction::STOP_RECORD:
347 StopRecordPlay();
348 break;
349 case HMIAction::LOAD_MAPS:
350 ReloadMaps();
351 break;
352 default:
353 AERROR << "HMIAction not implemented, yet!";
354 return false;
355 }
356 return true;
357}
358
359bool HMIWorker::Trigger(const HMIAction action, const std::string &value) {
360 AINFO << "HMIAction " << HMIAction_Name(action) << "(" << value
361 << ") was triggered!";
362 bool ret = true;
363 switch (action) {
364 case HMIAction::CHANGE_MODE:
365 ChangeMode(value);
366 break;
367 case HMIAction::CHANGE_MAP:
368 ret = ChangeMap(value);
369 // after change map;if sim_control is enabled,restart adc position
370 // with new map and sim control
371 SimControlManager::Instance()->Restart();
372 break;
373 case HMIAction::CHANGE_VEHICLE:
374 ChangeVehicle(value);
375 break;
376 case HMIAction::START_MODULE:
377 StartModule(value);
378 AddExpectedModules(action);
379 break;
380 case HMIAction::STOP_MODULE:
381 StopModule(value);
382 break;
383 case HMIAction::DELETE_SCENARIO_SET:
384 DeleteScenarioSet(value);
385 break;
386 case HMIAction::CHANGE_DYNAMIC_MODEL:
387 ChangeDynamicModel(value);
388 break;
389 case HMIAction::DELETE_DYNAMIC_MODEL:
390 DeleteDynamicModel(value);
391 break;
392 case HMIAction::DELETE_RECORD:
393 DeleteRecord(value);
394 break;
395 case HMIAction::CHANGE_RECORD:
396 ChangeRecord(value);
397 break;
398 case HMIAction::CHANGE_RTK_RECORD:
399 ChangeRtkRecord(value);
400 break;
401 case HMIAction::CHANGE_OPERATION:
402 ChangeOperation(value);
403 break;
404 case HMIAction::DELETE_VEHICLE_CONF:
405 DeleteVehicleConfig(value);
406 case HMIAction::DELETE_V2X_CONF:
407 DeleteV2xConfig(value);
408 break;
409 case HMIAction::DELETE_MAP:
410 DeleteMap(value);
411 break;
412 case HMIAction::LOAD_RECORD:
413 LoadRecordAndChangeStatus(value);
414 break;
415 default:
416 AERROR << "HMIAction not implemented, yet!";
417 return false;
418 }
419 return ret;
420}
421
422void HMIWorker::SubmitAudioEvent(const uint64_t event_time_ms,
423 const int obstacle_id, const int audio_type,
424 const int moving_result,
425 const int audio_direction,
426 const bool is_siren_on) {
427 std::shared_ptr<AudioEvent> audio_event = std::make_shared<AudioEvent>();
428 apollo::common::util::FillHeader("HMI", audio_event.get());
429 // Here we reuse the header time field as the event occurring time.
430 // A better solution might be adding an event time field to DriveEvent proto
431 // to make it clear.
432 audio_event->mutable_header()->set_timestamp_sec(
433 static_cast<double>(event_time_ms) / 1000.0);
434 audio_event->set_id(obstacle_id);
435 audio_event->set_audio_type(
436 static_cast<apollo::audio::AudioType>(audio_type));
437 audio_event->set_moving_result(
438 static_cast<apollo::audio::MovingResult>(moving_result));
439 audio_event->set_audio_direction(
440 static_cast<apollo::audio::AudioDirection>(audio_direction));
441 audio_event->set_siren_is_on(is_siren_on);
442
443 // Read the current localization pose
444 localization_reader_->Observe();
445 if (localization_reader_->Empty()) {
446 AERROR << "Failed to get localization associated with the audio event: "
447 << audio_event->DebugString() << "\n Localization reader is empty!";
448 return;
449 }
450
451 const std::shared_ptr<LocalizationEstimate> localization =
452 localization_reader_->GetLatestObserved();
453 audio_event->mutable_pose()->CopyFrom(localization->pose());
454 AINFO << "AudioEvent: " << audio_event->DebugString();
455
456 audio_event_writer_->Write(audio_event);
457}
458
459void HMIWorker::SubmitDriveEvent(const uint64_t event_time_ms,
460 const std::string &event_msg,
461 const std::vector<std::string> &event_types,
462 const bool is_reportable) {
463 std::shared_ptr<DriveEvent> drive_event = std::make_shared<DriveEvent>();
464 apollo::common::util::FillHeader("HMI", drive_event.get());
465 // TODO(xiaoxq): Here we reuse the header time field as the event occurring
466 // time. A better solution might be adding the field to DriveEvent proto to
467 // make it clear.
468 drive_event->mutable_header()->set_timestamp_sec(
469 static_cast<double>(event_time_ms) / 1000.0);
470 drive_event->set_event(event_msg);
471 drive_event->set_is_reportable(is_reportable);
472 for (const auto &type_name : event_types) {
473 DriveEvent::Type type;
474 if (DriveEvent::Type_Parse(type_name, &type)) {
475 drive_event->add_type(type);
476 } else {
477 AERROR << "Failed to parse drive event type:" << type_name;
478 }
479 }
480 drive_event_writer_->Write(drive_event);
481}
482
483void HMIWorker::SensorCalibrationPreprocess(const std::string &task_type) {
484 std::string start_command = absl::StrCat(
485 "nohup bash /apollo/modules/tools/sensor_calibration/extract_data.sh -t ",
486 task_type, " &");
487 System(start_command);
488}
489
490void HMIWorker::VehicleCalibrationPreprocess() {
491 std::string start_command = absl::StrCat(
492 "nohup bash /apollo/modules/tools/vehicle_calibration/preprocess.sh "
493 "--vehicle_type=\"",
494 status_.current_vehicle(), "\" --record_num=", record_count_, " &");
495 System(start_command);
496}
497
498bool HMIWorker::ChangeDrivingMode(const Chassis::DrivingMode mode) {
499 // Always reset to MANUAL mode before changing to other mode.
500 const std::string mode_name = Chassis::DrivingMode_Name(mode);
501 if (mode != Chassis::COMPLETE_MANUAL) {
502 if (!ChangeDrivingMode(Chassis::COMPLETE_MANUAL)) {
503 AERROR << "Failed to reset to MANUAL before changing to " << mode_name;
504 return false;
505 }
506 }
507
508 auto command = std::make_shared<ActionCommand>();
509
510 switch (mode) {
511 case Chassis::COMPLETE_MANUAL:
512 command->set_command(
514 break;
515 case Chassis::COMPLETE_AUTO_DRIVE:
516 command->set_command(
518 break;
519 default:
520 AFATAL << "Change driving mode to " << mode_name << " not implemented!";
521 return false;
522 }
523
524 static constexpr int kMaxTries = 3;
525 static constexpr auto kTryInterval = std::chrono::milliseconds(500);
526 for (int i = 0; i < kMaxTries; ++i) {
527 // Send driving action periodically until entering target driving mode.
528 common::util::FillHeader("HMI", command.get());
529 action_command_client_->SendRequest(command);
530
531 std::this_thread::sleep_for(kTryInterval);
532
533 chassis_reader_->Observe();
534 if (chassis_reader_->Empty()) {
535 AERROR << "No Chassis message received!";
536 } else if (chassis_reader_->GetLatestObserved()->driving_mode() == mode) {
537 return true;
538 }
539 }
540 AERROR << "Failed to change driving mode to " << mode_name;
541 return false;
542}
543
544bool HMIWorker::ChangeMap(const std::string &map_name) {
545 if (status_.current_map() == map_name) {
546 // Returns true if the map is switched to the same one.
547 return true;
548 }
549 return SelectAndReloadMap(map_name);
550}
551
552bool HMIWorker::SelectAndReloadMap(const std::string &map_name) {
553 const std::string *map_dir = FindOrNull(config_.maps(), map_name);
554 if (map_dir == nullptr) {
555 AERROR << "Unknown map " << map_name;
556 return false;
557 }
558
559 // Load the map first and then change the currently selected map;this will
560 // cause interactive waiting for loading a large map takes a long time
561 SetGlobalFlag("map_dir", *map_dir, &FLAGS_map_dir);
562 ResetMode();
563 Json callback_res = callback_api_("MapServiceReloadMap", {});
564 {
565 // Update current_map status.
566 WLock wlock(status_mutex_);
567 status_.set_current_map(map_name);
568 status_changed_ = true;
569 }
570 return callback_res["result"];
571}
572
573void HMIWorker::UpdateModeModulesAndMonitoredComponents() {
574 status_.clear_modules();
575 status_.clear_modules_lock();
576 previous_modules_lock_.clear();
577 for (const auto &iter : current_mode_.modules()) {
578 status_.mutable_modules()->insert({iter.first, false});
579 status_.mutable_modules_lock()->insert({iter.first, false});
580 previous_modules_lock_.insert({iter.first, false});
581 }
582
583 // Update monitored components of current mode.
584 status_.clear_monitored_components();
585 for (const auto &iter : current_mode_.monitored_components()) {
586 status_.mutable_monitored_components()->insert({iter.first, {}});
587 }
588}
589
590void HMIWorker::ChangeVehicle(const std::string &vehicle_name) {
591 const std::string *vehicle_dir = FindOrNull(config_.vehicles(), vehicle_name);
592 if (vehicle_dir == nullptr) {
593 AERROR << "Unknown vehicle " << vehicle_name;
594 return;
595 }
596 std::string current_mode;
597 {
598 // Update current_vehicle status.
599 WLock wlock(status_mutex_);
600 current_mode = status_.current_mode();
601 if (status_.current_vehicle() == vehicle_name) {
602 return;
603 }
604 try {
605 // try to get vehicle type from calibration data directory
606 // TODO(jinping): add vehicle config specs and move to vehicle config
607 const std::string vehicle_type_file_path = *vehicle_dir + "/vehicle_type";
608 std::string vehicle_type_str;
609 cyber::common::GetContent(vehicle_type_file_path, &vehicle_type_str);
610 int vehicle_type = std::stoi(vehicle_type_str);
611 status_.set_current_vehicle_type(vehicle_type);
612 } catch (const std::exception &e) {
613 AWARN << "get vehicle type config failed: " << e.what();
614 status_.clear_current_vehicle_type();
615 }
616 status_.set_current_vehicle(vehicle_name);
617 status_changed_ = true;
618 }
619 ResetMode();
620 // before reset mode
621 HMIMode vehicle_defined_mode;
622 const std::string mode_config_path = config_.modes().at(current_mode);
623 if (LoadVehicleDefinedMode(mode_config_path, *vehicle_dir,
624 &vehicle_defined_mode)) {
625 MergeToCurrentMode(&vehicle_defined_mode);
626 } else {
627 // modules may have been modified the last time selected a vehicle
628 // need to be recovery by load mode
629 current_mode_ = util::HMIUtil::LoadMode(mode_config_path);
630 }
631 {
632 WLock wlock(status_mutex_);
633 UpdateModeModulesAndMonitoredComponents();
634 }
635 ACHECK(VehicleManager::Instance()->UseVehicle(*vehicle_dir));
636 // Restart Fuel Monitor
637 auto *monitors = FuelMonitorManager::Instance()->GetCurrentMonitors();
638 if (monitors != nullptr) {
639 for (const auto &monitor : *monitors) {
640 if (monitor.second->IsEnabled()) {
641 monitor.second->Restart();
642 }
643 }
644 }
645}
646
647void HMIWorker::MergeToCurrentMode(HMIMode *mode) {
648 current_mode_.clear_modules();
649 current_mode_.clear_cyber_modules();
650 current_mode_.clear_monitored_components();
651 current_mode_.mutable_modules()->swap(*(mode->mutable_modules()));
652 current_mode_.mutable_monitored_components()->swap(
653 *(mode->mutable_monitored_components()));
654}
655
656void HMIWorker::ChangeMode(const std::string &mode_name) {
657 if (!ContainsKey(config_.modes(), mode_name)) {
658 AERROR << "Cannot change to unknown mode " << mode_name;
659 return;
660 }
661
662 {
663 RLock rlock(status_mutex_);
664 // Skip if mode doesn't actually change.
665 if (status_.current_mode() == mode_name) {
666 return;
667 }
668 }
669 ResetMode();
670 std::string default_operation_str = "";
671 {
672 WLock wlock(status_mutex_);
673 status_.set_current_mode(mode_name);
674 current_mode_ = util::HMIUtil::LoadMode(config_.modes().at(mode_name));
675 // for vehicle self-defined module
676 HMIMode vehicle_defined_mode;
677 const std::string *vehicle_dir =
678 FindOrNull(config_.vehicles(), status_.current_vehicle());
679 if (vehicle_dir != nullptr &&
680 LoadVehicleDefinedMode(config_.modes().at(mode_name), *vehicle_dir,
681 &vehicle_defined_mode)) {
682 MergeToCurrentMode(&vehicle_defined_mode);
683 }
684 UpdateModeModulesAndMonitoredComponents();
685
686 status_.clear_other_components();
687 for (const auto &iter : current_mode_.other_components()) {
688 status_.mutable_other_components()->insert({iter.first, {}});
689 }
690
691 // update operations of current mode
692 status_.clear_operations();
693 status_.mutable_operations()->CopyFrom(current_mode_.operations());
694
695 // Temporarily used for simulation plugins, removed when simulation is used
696 // as a standalone mode.
697 if ((mode_name == "Pnc" || mode_name == "Default") &&
698 PackageExist("simulator-plugin")) {
699 status_.add_operations(HMIModeOperation::Scenario_Sim);
700 }
701
702 if (current_mode_.has_default_operation()) {
703 default_operation_str =
704 HMIModeOperation_Name(current_mode_.default_operation());
705 }
706 status_changed_ = true;
707 }
708 // Because the change operation involves the state change of the sim control
709 // therefore, the function change operation is used when loading the mode;
710 // not only the Hmi status is changed; the sim control is also switched on and
711 // off.
712 if (!default_operation_str.empty()) {
713 ChangeOperation(default_operation_str);
714 }
715 FuelMonitorManager::Instance()->SetCurrentMode(mode_name);
716 KVDB::Put(FLAGS_current_mode_db_key, mode_name);
717}
718
719void HMIWorker::StartModule(const std::string &module) {
720 const Module *module_conf = FindOrNull(current_mode_.modules(), module);
721 if (module_conf != nullptr) {
722 {
723 WLock wlock(status_mutex_);
724 LockModule(module, true);
725 }
726 System(module_conf->start_command());
727 } else {
728 AERROR << "Cannot find module " << module;
729 }
730}
731
732void HMIWorker::StopModule(const std::string &module) {
733 const Module *module_conf = FindOrNull(current_mode_.modules(), module);
734 if (module_conf != nullptr) {
735 {
736 WLock wlock(status_mutex_);
737 LockModule(module, true);
738 }
739 System(module_conf->stop_command());
740 } else {
741 AERROR << "Cannot find module " << module;
742 }
743}
744
745HMIStatus HMIWorker::GetStatus() const {
746 RLock rlock(status_mutex_);
747 return status_;
748}
749
750void HMIWorker::SetupMode() {
751 {
752 WLock wlock(status_mutex_);
753 status_.set_backend_shutdown(false);
754 }
755 for (const auto &iter : current_mode_.modules()) {
756 {
757 WLock wlock(status_mutex_);
758 auto modules = status_.modules();
759 if (!modules[iter.first]) {
760 LockModule(iter.first, true);
761 }
762 }
763 System(iter.second.start_command());
764 }
765}
766
767void HMIWorker::ResetMode() {
768 {
769 // Clearing the module and lock will cause the backend to trigger automatic
770 // shutdown.
771 WLock wlock(status_mutex_);
772 status_.set_backend_shutdown(true);
773 }
774 for (const auto &iter : current_mode_.modules()) {
775 {
776 WLock wlock(status_mutex_);
777 auto modules = status_.modules();
778 if (modules[iter.first]) {
779 LockModule(iter.first, true);
780 }
781 }
782 System(iter.second.stop_command());
783 }
784 record_count_ = 0;
785}
786
787void HMIWorker::StatusUpdateThreadLoop() {
788 constexpr int kLoopIntervalMs = 200;
789 while (!stop_) {
790 std::this_thread::sleep_for(std::chrono::milliseconds(kLoopIntervalMs));
791 UpdateComponentStatus();
792 bool status_changed = false;
793 {
794 WLock wlock(status_mutex_);
795 status_changed = status_changed_;
796 status_changed_ = false;
797 }
798 // If status doesn't change, check if we reached update interval.
799 if (!status_changed) {
800 static double next_update_time = 0;
801 const double now = Clock::NowInSeconds();
802 if (now < next_update_time) {
803 continue;
804 }
805 next_update_time = now + FLAGS_status_publish_interval;
806 }
807
808 // Trigger registered status change handlers.
809 HMIStatus status = GetStatus();
810 for (const auto handler : status_update_handlers_) {
811 handler(status_changed, &status);
812 }
813 }
814}
815
816void HMIWorker::ResetComponentStatusTimer() {
817 last_status_received_s_ = Clock::NowInSeconds();
818 last_status_fingerprint_ = 0;
819}
820
821void HMIWorker::UpdateComponentStatus() {
822 const double now = Clock::NowInSeconds();
823 if (now - last_status_received_s_.load() > FLAGS_monitor_timeout_threshold) {
824 if (!monitor_timed_out_) {
825 WLock wlock(status_mutex_);
826
827 const uint64_t now_ms = static_cast<uint64_t>(now * 2e3);
828 static constexpr bool kIsReportable = true;
829 SubmitDriveEvent(now_ms, "Monitor timed out", {"PROBLEM"}, kIsReportable);
830 AWARN << "System fault. Auto disengage.";
831 Trigger(HMIAction::DISENGAGE);
832
833 for (auto &monitored_component :
834 *status_.mutable_monitored_components()) {
835 monitored_component.second.set_status(ComponentStatus::UNKNOWN);
836 monitored_component.second.set_message(
837 "Status not reported by Monitor.");
838 }
839 status_changed_ = true;
840 }
841 monitor_timed_out_ = true;
842 } else {
843 monitor_timed_out_ = false;
844 }
845}
846
847void HMIWorker::GetScenarioResourcePath(std::string *scenario_resource_path) {
848 CHECK_NOTNULL(scenario_resource_path);
849 const std::string home = cyber::common::GetEnv("HOME");
850 *scenario_resource_path = home + FLAGS_resource_scenario_path;
851}
852
853void HMIWorker::ChangeDynamicModel(const std::string &dynamic_model_name) {
854 // To avoid toggle sim control and always choose simulation perfect control
855 // {
856 // RLock rlock(status_mutex_);
857 // // Skip if mode doesn't actually change.
858 // if (status_.current_dynamic_model() == dynamic_model_name) {
859 // return;
860 // }
861 // }
862 if (dynamic_model_name.empty()) {
863 AERROR << "Failed to change empty dynamic model!";
864 return;
865 }
866 auto sim_control_manager = SimControlManager::Instance();
867 if (!sim_control_manager->IsEnabled()) {
868 AERROR << "Sim control is not enabled!";
869 return;
870 }
871
872 if (!sim_control_manager->ChangeDynamicModel(dynamic_model_name)) {
873 // badcase1:sim control is not enabled. badcase2:miss params
874 // badcase3:change dynamic model is not registered. resolution:return with
875 // no action,keep sim control not enabled or use original dynamic model!
876 AERROR << "Failed to change dynamic model! Please check if the param is "
877 "valid!";
878 return;
879 }
880 std::string current_dynamic_model_name = dynamic_model_name;
881 {
882 WLock wlock(status_mutex_);
883 status_.set_current_dynamic_model(dynamic_model_name);
884 status_changed_ = true;
885 }
886 return;
887}
888
889bool HMIWorker::UpdateDynamicModelToStatus(
890 const std::string &dynamic_model_name) {
891 auto sim_control_manager = SimControlManager::Instance();
892 if (!sim_control_manager->IsEnabled()) {
893 AERROR << "Sim control is not enabled or missing dynamic model name "
894 "param!";
895 return false;
896 }
897
898 if (!sim_control_manager->AddDynamicModel(dynamic_model_name)) {
899 AERROR << "Failed to add dynamic model to local dynamic model list for "
900 "register failed!";
901 return false;
902 }
903 {
904 WLock wlock(status_mutex_);
905 for (const auto &iter : status_.dynamic_models()) {
906 if (iter == dynamic_model_name) {
907 AERROR << "Do not need to add new dynamic model for is duplicate!";
908 return true;
909 }
910 }
911 status_.add_dynamic_models(dynamic_model_name);
912 status_changed_ = true;
913 }
914 return true;
915}
916
917bool HMIWorker::LoadDynamicModels() {
918 auto sim_control_manager = SimControlManager::Instance();
919 nlohmann::json load_res;
920 if (sim_control_manager->IsEnabled()) {
921 load_res = sim_control_manager->LoadDynamicModels();
922 } else {
923 AERROR << "Sim control is not enabled!";
924 return false;
925 }
926 if (!load_res.contains("result") || !load_res["result"]) {
927 return false;
928 }
929
930 {
931 WLock wlock(status_mutex_);
932 auto dynamic_models = status_.mutable_dynamic_models();
933 // clear old data
934 for (auto iter = dynamic_models->begin(); iter != dynamic_models->end();) {
935 iter = dynamic_models->erase(iter);
936 }
937 for (const auto &dynamic_model : load_res["loaded_dynamic_models"]) {
938 status_.add_dynamic_models(dynamic_model);
939 }
940 status_changed_ = true;
941 }
942 return true;
943}
944
945void HMIWorker::DeleteScenarioSet(const std::string &scenario_set_id) {
946 if (scenario_set_id.empty()) {
947 return;
948 }
949 std::string directory_path;
950 GetScenarioResourcePath(&directory_path);
951 directory_path = directory_path + scenario_set_id;
952 if (!cyber::common::PathExists(directory_path)) {
953 AERROR << "Failed to find scenario_set!";
954 return;
955 }
956 std::string command = "rm -fr " + directory_path;
957 // use cyber::common::removeFiles do not support sub-directory
958 // use rmdir do not support not empty directory
959 if (std::system(command.data()) != 0) {
960 AERROR << "Failed to delete scenario set directory for: "
961 << std::strerror(errno);
962 return;
963 }
964 return;
965}
966
967void HMIWorker::DeleteDynamicModel(const std::string &dynamic_model_name) {
968 if (dynamic_model_name.empty()) {
969 AERROR << "Invalid param:empty dynamic model name!";
970 return;
971 }
972 {
973 RLock rlock(status_mutex_);
974 // do not allowed remove changed current dynamic model
975 if (dynamic_model_name == status_.current_dynamic_model()) {
976 AERROR << "Cannot delete current dynamic model!";
977 return;
978 }
979 if (dynamic_model_name == FLAGS_sim_perfect_control) {
980 AERROR << "Cannot delete default sim control:SimPerfectControl!";
981 return;
982 }
983 }
984 auto sim_control_manager = SimControlManager::Instance();
985 if (!sim_control_manager->IsEnabled()) {
986 AERROR << "Sim control is not enabled!";
987 return;
988 }
989 if (!sim_control_manager->DeleteDynamicModel(dynamic_model_name)) {
990 // badcase1: sim control is not enable. badcase2: miss param
991 // badcase3: Failed to delete file
992 AERROR << "Failed to delete dynamic model!";
993 return;
994 }
995 {
996 WLock wlock(status_mutex_);
997 auto iter = status_.dynamic_models().begin();
998 while (iter != status_.dynamic_models().end()) {
999 if (*iter == dynamic_model_name) {
1000 break;
1001 }
1002 iter++;
1003 }
1004 if (iter != status_.dynamic_models().end()) {
1005 status_.mutable_dynamic_models()->erase(iter);
1006 status_changed_ = true;
1007 } else {
1008 AWARN << "Can not find dynamic model to delete!";
1009 }
1010 }
1011 return;
1012}
1013
1014void HMIWorker::GetRecordPath(std::string *record_path) {
1015 CHECK_NOTNULL(record_path);
1016 const std::string home = cyber::common::GetEnv("HOME");
1017 *record_path = home + FLAGS_resource_record_path;
1018}
1019
1020bool HMIWorker::handlePlayRecordProcess(const std::string &action_type) {
1021 std::string record_id;
1022 PlayRecordStatus current_play_record_status;
1023 PlayRecordStatus expected_play_record_status;
1024 PlayRecordStatus reasonable_play_record_status;
1025 {
1026 RLock rlock(status_mutex_);
1027 auto record_status = status_.current_record_status();
1028 record_id = record_status.current_record_id();
1029 current_play_record_status = record_status.play_record_status();
1030 if (record_id.empty()) {
1031 AERROR << "Failed to pause record for record has not been selected"
1032 "or process is not exists!";
1033 return false;
1034 }
1035 if (!RecordIsLoaded(record_id)) {
1036 AERROR << "Failed to pause record for record has not been loaded!";
1037 return false;
1038 }
1039 }
1040 if (action_type.compare("continue") == 0) {
1041 expected_play_record_status = PlayRecordStatus::RUNNING;
1042 reasonable_play_record_status = PlayRecordStatus::PAUSED;
1043 } else if (action_type.compare("pause") == 0) {
1044 expected_play_record_status = PlayRecordStatus::PAUSED;
1045 reasonable_play_record_status = PlayRecordStatus::RUNNING;
1046 } else {
1047 AERROR << "Invalid action type for play record.";
1048 return false;
1049 }
1050 if (reasonable_play_record_status != current_play_record_status) {
1051 return false;
1052 }
1053 auto *record_player_factory = RecordPlayerFactory::Instance();
1054 auto player_ptr = record_player_factory->GetRecordPlayer(record_id);
1055 if (!player_ptr) {
1056 AERROR << "Failed to get record player.";
1057 return false;
1058 }
1059 player_ptr->HandleNohupThreadStatus();
1060
1061 {
1062 WLock wlock(status_mutex_);
1063 status_.mutable_current_record_status()->set_play_record_status(
1064 expected_play_record_status);
1065 status_changed_ = true;
1066 }
1067 record_player_factory->IncreaseRecordPriority(record_id);
1068 return true;
1069}
1070
1071bool HMIWorker::RePlayRecord() {
1072 std::string record_id;
1073 {
1074 RLock rlock(status_mutex_);
1075 auto record_status = status_.current_record_status();
1076 record_id = record_status.current_record_id();
1077 if (record_status.current_record_id().empty()) {
1078 AERROR << "Failed to play record for record has not been selected!";
1079 return false;
1080 }
1081 if (!RecordIsLoaded(record_id)) {
1082 AERROR << "Failed to play record for record has not been loaded!";
1083 return false;
1084 }
1085 if (record_status.play_record_status() == PlayRecordStatus::RUNNING) {
1086 AERROR << "Record has been played,ignore dumplicate request.";
1087 return false;
1088 }
1089 }
1090 std::string record_path;
1091 GetRecordPath(&record_path);
1092 record_path = record_path + record_id + ".record";
1093
1094 if (!cyber::common::PathExists(record_path)) {
1095 AERROR << "Failed to find record!";
1096 return false;
1097 }
1098 // play the record
1099 auto *record_player_factory = RecordPlayerFactory::Instance();
1100 auto player_ptr = record_player_factory->GetRecordPlayer(record_id);
1101 bool play_record_res = (player_ptr != nullptr);
1102 PlayRecordStatus play_record_status;
1103 if (!play_record_res) {
1104 AERROR << "Failed to get record related player";
1105 play_record_status = PlayRecordStatus::CLOSED;
1106 } else {
1107 player_ptr->PreloadPlayRecord();
1108 player_ptr->NohupPlayRecord();
1109 // get channel msgs for frontend after start play record
1110 callback_api_("GetDataHandlerConf", {});
1111 play_record_status = PlayRecordStatus::RUNNING;
1112 }
1113 {
1114 WLock wlock(status_mutex_);
1115 auto record_status = status_.mutable_current_record_status();
1116 record_status->set_play_record_status(play_record_status);
1117 status_changed_ = true;
1118 }
1119 record_player_factory->IncreaseRecordPriority(record_id);
1120 return play_record_res;
1121}
1122
1123bool HMIWorker::ResetRecordProgress(const double &progress) {
1124 std::string record_id;
1125 double total_time_s;
1126 PlayRecordStatus last_record_status;
1127 {
1128 RLock rlock(status_mutex_);
1129 auto record_status = status_.current_record_status();
1130 record_id = record_status.current_record_id();
1131 last_record_status = record_status.play_record_status();
1132 if (record_status.current_record_id().empty()) {
1133 AERROR << "Failed to reset record progress for record has not been "
1134 "selected!";
1135 return false;
1136 }
1137 if (!RecordIsLoaded(record_id)) {
1138 AERROR << "Failed to reset record progress for record has not been "
1139 "loaded!";
1140 return false;
1141 }
1142 total_time_s = status_.records().at(record_id).total_time_s();
1143 }
1144 AERROR << "total : " << total_time_s;
1145 if (progress > total_time_s) {
1146 AERROR << "Failed to reset record progress for progress exceeds the "
1147 "record's total time.";
1148 return false;
1149 }
1150 auto *record_player_factory = RecordPlayerFactory::Instance();
1151 auto player_ptr = record_player_factory->GetRecordPlayer(record_id);
1152 if (!player_ptr) {
1153 AERROR << "Failed to get record player.";
1154 return false;
1155 }
1156 player_ptr->Reset();
1157 player_ptr->PreloadPlayRecord(
1158 progress, (last_record_status != PlayRecordStatus::RUNNING));
1159 player_ptr->NohupPlayRecord();
1160 // When a record is selected and the progress is reset; we consider
1161 // the record to be stuck at the current progress in a paused state
1162 // to keep logic consistent
1163 if (last_record_status == PlayRecordStatus::CLOSED) {
1164 last_record_status = PlayRecordStatus::PAUSED;
1165 }
1166 // get channel msgs for frontend after start play record
1167 callback_api_("GetDataHandlerConf", {});
1168 {
1169 WLock wlock(status_mutex_);
1170 auto record_status = status_.mutable_current_record_status();
1171 record_status->set_play_record_status(last_record_status);
1172 record_status->set_curr_time_s(progress);
1173 status_changed_ = true;
1174 }
1175 record_player_factory->IncreaseRecordPriority(record_id);
1176 return true;
1177}
1178
1179void HMIWorker::StopRecordPlay(const std::string &record_id) {
1180 std::string curr_record_id = "";
1181 {
1182 RLock rlock(status_mutex_);
1183 curr_record_id = status_.current_record_status().current_record_id();
1184 }
1185 if (!record_id.empty()) {
1186 curr_record_id = record_id;
1187 }
1188 if (!RecordIsLoaded(curr_record_id)) {
1189 AERROR << "Failed to stop record player under unloaded status!";
1190 return;
1191 }
1192 auto *record_player_factory = RecordPlayerFactory::Instance();
1193 auto player_ptr = record_player_factory->GetRecordPlayer(curr_record_id);
1194 if (!player_ptr) {
1195 AERROR << "Failed to get record player to reset.";
1196 return;
1197 }
1198 player_ptr->Reset();
1199 {
1200 WLock wlock(status_mutex_);
1201 auto record_status = status_.mutable_current_record_status();
1202 record_status->set_play_record_status(PlayRecordStatus::CLOSED);
1203 record_status->clear_curr_time_s();
1204 }
1205 status_changed_ = true;
1206}
1207
1208bool HMIWorker::RecordIsLoaded(const std::string &record_id) {
1209 {
1210 RLock rlock(status_mutex_);
1211 auto iter = status_.records().find(record_id);
1212 return iter != status_.records().end() &&
1213 (iter->second.load_record_status() == LoadRecordStatus::LOADED);
1214 }
1215}
1216
1217void HMIWorker::ChangeRecord(const std::string &record_id) {
1218 std::string last_record_id;
1219 {
1220 RLock rlock(status_mutex_);
1221 auto status_records = status_.mutable_records();
1222 auto iter = status_records->find(record_id);
1223 if (iter == status_records->end()) {
1224 AERROR << "Cannot change to unknown record!";
1225 return;
1226 }
1227 if (!RecordIsLoaded(record_id)) {
1228 AERROR << "Cannot change to unloaded record, load this record before!";
1229 return;
1230 }
1231 last_record_id = status_.current_record_status().current_record_id();
1232 }
1233 if (!last_record_id.empty()) {
1234 StopRecordPlay(last_record_id);
1235 }
1236 // clear last channel msgs info for frontend after change record
1237 callback_api_("ClearDataHandlerConfChannelMsgs", {});
1238 WLock wlock(status_mutex_);
1239 status_.mutable_current_record_status()->set_current_record_id(record_id);
1240 auto *record_player_factory = RecordPlayerFactory::Instance();
1241 record_player_factory->SetCurrentRecord(record_id);
1242 record_player_factory->IncreaseRecordPriority(record_id);
1243 status_changed_ = true;
1244 return;
1245}
1246
1247void HMIWorker::ClearInvalidResourceUnderChangeOperation(
1248 const HMIModeOperation operation) {
1249 ClearInvalidRecordStatus(operation);
1250 HMIModeOperation old_operation;
1251 {
1252 RLock rlock(status_mutex_);
1253 old_operation = status_.current_operation();
1254 }
1255 // dynamic model resource clear and sim control manager start/stop
1256 // sim control status changed when operation change
1257 auto sim_control_manager = SimControlManager::Instance();
1258 auto iter = std::find(OperationBasedOnSimControl.begin(),
1259 OperationBasedOnSimControl.end(), operation);
1260 if (iter != OperationBasedOnSimControl.end()) {
1261 sim_control_manager->Start();
1262 } else {
1263 sim_control_manager->Stop();
1264 // clear DynamicModel related info
1265 {
1266 WLock wlock(status_mutex_);
1267 status_.set_current_dynamic_model("");
1268 status_.clear_dynamic_models();
1269 status_changed_ = true;
1270 }
1271 }
1272 if (old_operation == HMIModeOperation::Record) {
1273 // change from record need to clear record info.
1274 ClearRecordInfo();
1275 }
1276 if (old_operation == HMIModeOperation::Waypoint_Follow) {
1277 // clear selected rtk record
1278 ClearRtkRecordInfo();
1279 }
1280}
1281
1282void HMIWorker::ChangeOperation(const std::string &operation_str) {
1283 HMIModeOperation operation;
1284 if (!HMIModeOperation_Parse(operation_str, &operation)) {
1285 AERROR << "Invalid HMI operation string: " << operation_str;
1286 return;
1287 }
1288 {
1289 RLock rlock(status_mutex_);
1290 if (status_.current_mode().empty()) {
1291 AERROR << "Please select mode!";
1292 return;
1293 }
1294 auto status_operations = status_.operations();
1295 auto iter = status_operations.begin();
1296 for (; iter != status_operations.end(); iter++) {
1297 if (*iter == operation) {
1298 break;
1299 }
1300 }
1301 if (iter == status_operations.end()) {
1302 AERROR << "Cannot change to unknown operation!";
1303 return;
1304 }
1305 }
1306 ClearInvalidResourceUnderChangeOperation(operation);
1307 {
1308 WLock wlock(status_mutex_);
1309 status_.set_current_operation(operation);
1310 status_changed_ = true;
1311 }
1312 return;
1313}
1314
1315bool HMIWorker::ReadRecordInfo(const std::string &file,
1316 double *total_time_s) const {
1317 cyber::record::RecordFileReader file_reader;
1318 if (!file_reader.Open(file)) {
1319 AERROR << "open record file error. file: " << file;
1320 return false;
1321 }
1322 cyber::proto::Header hdr = file_reader.GetHeader();
1323 if (!hdr.is_complete()) {
1324 AERROR << "record is not complete, can not be used. file: " << file;
1325 return false;
1326 }
1327 auto begin_time_s = static_cast<double>(hdr.begin_time()) / 1e9;
1328 auto end_time_s = static_cast<double>(hdr.end_time()) / 1e9;
1329 double loop_time_s = end_time_s - begin_time_s;
1330 *total_time_s = std::round(loop_time_s * 1e2) / 1e2;
1331 return true;
1332}
1333
1334bool HMIWorker::UpdateMapToStatus(const std::string &map_tar_name) {
1335 if (map_tar_name.empty()) {
1336 ReloadMaps();
1337 return true;
1338 }
1339 std::string map_dir = FLAGS_maps_data_path + "/";
1340 std::string map_name_prefix;
1341 int index = map_tar_name.rfind(".tar.xz");
1342 if (index != -1 && map_tar_name[0] != '.') {
1343 map_name_prefix = map_tar_name.substr(0, index);
1344 map_dir = map_dir + map_name_prefix;
1345 } else {
1346 AERROR << "The map name does not meet the standard!" << map_tar_name;
1347 return false;
1348 }
1349 if (!cyber::common::PathExists(map_dir)) {
1350 AERROR << "Failed to find maps!";
1351 return false;
1352 }
1353 map_name_prefix = util::HMIUtil::TitleCase(map_name_prefix);
1354 {
1355 WLock wlock(status_mutex_);
1356 auto iter = status_.maps().begin();
1357 for (; iter != status_.maps().end(); iter++) {
1358 if (*iter == map_name_prefix) {
1359 break;
1360 }
1361 }
1362 if (iter != status_.maps().end()) {
1363 return true;
1364 }
1365 status_.add_maps(map_name_prefix);
1366 status_changed_ = true;
1367 }
1368 return true;
1369}
1370
1371bool HMIWorker::LoadRecordAndChangeStatus(const std::string &record_name) {
1372 std::string record_file_path;
1373 {
1374 RLock rlock(status_mutex_);
1375 auto &status_records = status_.records();
1376 auto iter = status_records.find(record_name);
1377 if (iter == status_records.end()) {
1378 AERROR << "Cannot load unknown record!";
1379 return false;
1380 }
1381 if (RecordIsLoaded(record_name)) {
1382 AERROR << "Cannot load already loaded record.";
1383 return false;
1384 }
1385 if (iter->second.record_file_path().empty()) {
1386 AERROR << "Cannot load record without record file path!";
1387 return false;
1388 }
1389 record_file_path = iter->second.record_file_path();
1390 }
1391 {
1392 WLock wlock(status_mutex_);
1393 auto status_records = status_.mutable_records();
1394 (*status_records)[record_name].set_load_record_status(
1395 LoadRecordStatus::LOADING);
1396 }
1397 double total_time_s;
1398 if (LoadRecord(record_name, record_file_path, &total_time_s)) {
1399 {
1400 WLock wlock(status_mutex_);
1401 auto status_records = status_.mutable_records();
1402 (*status_records)[record_name].set_load_record_status(
1403 LoadRecordStatus::LOADED);
1404 (*status_records)[record_name].set_total_time_s(total_time_s);
1405 }
1406 RecordPlayerFactory::Instance()->IncreaseRecordPriority(record_name);
1407 } else {
1408 {
1409 WLock wlock(status_mutex_);
1410 auto status_records = status_.mutable_records();
1411 (*status_records)[record_name].set_load_record_status(
1412 LoadRecordStatus::NOT_LOAD);
1413 }
1414 }
1415 return true;
1416}
1417
1418bool HMIWorker::LoadRecord(const std::string &record_name,
1419 const std::string &record_file_path,
1420 double *total_time_s) {
1421 if (RecordIsLoaded(record_name)) {
1422 AERROR << "Record is loaded,no need to load";
1423 return false;
1424 }
1425 // check if record player factory can continue load
1426 auto record_player_factory = RecordPlayerFactory::Instance();
1427 if (!record_player_factory->EnableContinueLoad()) {
1428 // can not load record,need to remove lru record
1429 std::string remove_record_id;
1430 if (record_player_factory->RemoveLRURecord(&remove_record_id)) {
1431 // remove successfully, change removed record status
1432 {
1433 WLock wlock(status_mutex_);
1434 auto status_records = status_.mutable_records();
1435 (*status_records)[remove_record_id].set_load_record_status(
1436 LoadRecordStatus::NOT_LOAD);
1437 (*status_records)[remove_record_id].clear_total_time_s();
1438 }
1439 }
1440 }
1441 if (!ReadRecordInfo(record_file_path, total_time_s)) {
1442 return false;
1443 }
1444 if (!record_player_factory->RegisterRecordPlayer(record_name,
1445 record_file_path)) {
1446 return false;
1447 }
1448 return true;
1449}
1450
1451bool HMIWorker::LoadRecords() {
1452 std::string directory_path;
1453 auto *record_player_factory = RecordPlayerFactory::Instance();
1454 GetRecordPath(&directory_path);
1455 if (!cyber::common::PathExists(directory_path)) {
1456 AERROR << "Failed to find records!";
1457 return false;
1458 }
1459 DIR *directory = opendir(directory_path.c_str());
1460 if (directory == nullptr) {
1461 AERROR << "Cannot open record directory" << directory_path;
1462 return false;
1463 }
1464 struct dirent *file;
1465 google::protobuf::Map<std::string, LoadRecordInfo> new_records;
1466 while ((file = readdir(directory)) != nullptr) {
1467 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
1468 continue;
1469 }
1470 if (file->d_type == DT_DIR) {
1471 continue;
1472 }
1473 const std::string record_id = file->d_name;
1474 const int index = record_id.rfind(".record");
1475 // Skip format that dv cannot parse: record not ending in record
1476 size_t record_suffix_length = 7;
1477 if (record_id.length() - index != record_suffix_length) {
1478 continue;
1479 }
1480 if (index != -1 && record_id[0] != '.') {
1481 const std::string local_record_resource = record_id.substr(0, index);
1482 const std::string record_file_path = directory_path + "/" + record_id;
1483 double total_time_s;
1484 // Already loaded, no need to change status
1485 if (RecordIsLoaded(local_record_resource)) {
1486 continue;
1487 }
1488 // already reach max preload num,no load only get basic info
1489 if (!record_player_factory->EnableContinuePreload()) {
1490 new_records[local_record_resource].set_load_record_status(
1491 LoadRecordStatus::NOT_LOAD);
1492 new_records[local_record_resource].set_record_file_path(
1493 record_file_path);
1494 continue;
1495 }
1496 // failed to load record,continue
1497 if (!LoadRecord(local_record_resource, record_file_path, &total_time_s)) {
1498 continue;
1499 }
1500 // Successfully load record, change hmi status
1501 new_records[local_record_resource].set_total_time_s(total_time_s);
1502 new_records[local_record_resource].set_load_record_status(
1503 LoadRecordStatus::LOADED);
1504 new_records[local_record_resource].set_record_file_path(record_file_path);
1505 }
1506 }
1507 closedir(directory);
1508 {
1509 WLock wlock(status_mutex_);
1510 auto status_records = status_.mutable_records();
1511 for (auto iter = new_records.begin(); iter != new_records.end(); iter++) {
1512 (*status_records)[iter->first] = iter->second;
1513 }
1514 status_changed_ = true;
1515 }
1516 return true;
1517}
1518
1519void HMIWorker::DeleteMap(const std::string &map_name) {
1520 std::string title_map_name = util::HMIUtil::TitleCase(map_name);
1521 if (map_name.empty()) {
1522 return;
1523 }
1524 std::string map_dir = FLAGS_maps_data_path + "/";
1525 std::string map_abs_path = map_dir + map_name;
1526 if (!cyber::common::PathExists(map_abs_path)) {
1527 AERROR << "Failed to get map path: " << map_abs_path;
1528 return;
1529 }
1530 {
1531 WLock wlock(status_mutex_);
1532 auto iter = status_.maps().begin();
1533 for (; iter != status_.maps().end(); iter++) {
1534 if (*iter == title_map_name) {
1535 break;
1536 }
1537 }
1538 if (iter == status_.maps().end()) {
1539 AERROR << "Faile to find map name";
1540 return;
1541 }
1542 if (status_.current_map() == title_map_name) {
1543 AERROR << "Cann't delete current selected map";
1544 return;
1545 }
1546 status_.mutable_maps()->erase(iter);
1547 status_changed_ = true;
1548 }
1549
1550 std::string cmd = "rm -rf " + map_abs_path;
1551 if (std::system(cmd.data()) != 0) {
1552 AERROR << "Failed to delete map for: " << std::strerror(errno);
1553 return;
1554 }
1555 std::string tar_abs_path = map_dir + map_name + ".tar.xz";
1556
1557 if (cyber::common::PathExists(tar_abs_path)) {
1558 cmd = "rm -rf " + tar_abs_path;
1559 if (std::system(cmd.data()) != 0) {
1560 AERROR << "Failed to delete map tar file for: " << std::strerror(errno);
1561 }
1562 }
1563 return;
1564}
1565
1566void HMIWorker::DeleteRecord(const std::string &record_id) {
1567 if (record_id.empty()) {
1568 return;
1569 }
1570 std::string record_path;
1571 GetRecordPath(&record_path);
1572 const std::string record_abs_path = record_path + record_id + ".record";
1573 if (!cyber::common::PathExists(record_abs_path)) {
1574 AERROR << "Failed to get record path: " << record_abs_path;
1575 return;
1576 }
1577 // find the delete record if exist and judge the record whether playing now
1578 {
1579 RLock rlock(status_mutex_);
1580 auto &status_records = status_.records();
1581 if (status_records.find(record_id) == status_records.end()) {
1582 AERROR << "Failed to find record id: " << record_id;
1583 return;
1584 }
1585 if (record_id == status_.current_record_status().current_record_id()) {
1586 AERROR << "Cann't delete current selected record";
1587 return;
1588 }
1589 }
1590 // unregister record player from player factory
1591 auto *record_player_factory = RecordPlayerFactory::Instance();
1592 record_player_factory->UnregisterRecordPlayer(record_id);
1593 {
1594 WLock wlock(status_mutex_);
1595 status_.mutable_records()->erase(record_id);
1596 status_changed_ = true;
1597 }
1598
1599 // delete record from disk
1600 std::string command = "rm -rf " + record_abs_path;
1601 if (std::system(command.data()) != 0) {
1602 AERROR << "Failed to delete record for: " << std::strerror(errno);
1603 return;
1604 }
1605 // record may unzip from same name tar xz file,delete record file also need
1606 // to delete record tar xz file
1607 const std::string tar_abs_path = record_path + record_id + ".tar.xz";
1608 if (cyber::common::PathExists(tar_abs_path)) {
1609 command = "rm -rf " + tar_abs_path;
1610 if (std::system(command.data()) != 0) {
1611 AERROR << "Failed to delete record tar file for: "
1612 << std::strerror(errno);
1613 return;
1614 }
1615 }
1616 return;
1617}
1618
1619void HMIWorker::ReloadMaps() {
1620 WLock wlock(status_mutex_);
1621 config_.mutable_maps()->clear();
1622 *(config_.mutable_maps()) =
1623 util::HMIUtil::ListDirAsDict(FLAGS_maps_data_path);
1624 status_.clear_maps();
1625 for (const auto &map : config_.maps()) {
1626 status_.add_maps(map.first);
1627 }
1628 if (status_.current_map() != "") {
1629 // if current map is not empty, check whether it exists in config
1630 if (config_.maps().find(status_.current_map()) == config_.maps().end()) {
1631 // if not, set current map to empty string
1632 AINFO << "Current map is not in status. Reset it.";
1633 status_.set_current_map("");
1634 }
1635 }
1636 status_changed_ = true;
1637 return;
1638}
1639
1640bool HMIWorker::ReloadVehicles() {
1641 HMIConfig config =
1642 util::HMIUtil::LoadConfig(FLAGS_dv_plus_hmi_modes_config_path);
1643 std::string msg;
1644 config.SerializeToString(&msg);
1645
1646 WLock wlock(status_mutex_);
1647 config_.ParseFromString(msg);
1648 // status_.clear_modes();
1649 // status_.clear_maps();
1650 status_.clear_vehicles();
1651 // InitStatus();
1652 // Populate vehicles and current_vehicle.
1653 for (const auto &vehicle : config_.vehicles()) {
1654 status_.add_vehicles(vehicle.first);
1655 }
1656 status_changed_ = true;
1657 return true;
1658}
1659
1660void HMIWorker::UpdateCameraSensorChannelToStatus(
1661 const std::string &channel_name) {
1662 {
1663 WLock wlock(status_mutex_);
1664 if (status_.current_camera_sensor_channel() == channel_name) {
1665 AINFO << "Input channel name is current camera sensor channel";
1666 return;
1667 }
1668 status_.set_current_camera_sensor_channel(channel_name);
1669 status_changed_ = true;
1670 }
1671}
1672
1673void HMIWorker::UpdatePointCloudChannelToStatus(
1674 const std::string &channel_name) {
1675 {
1676 WLock wlock(status_mutex_);
1677 if (status_.current_point_cloud_channel() == channel_name) {
1678 AINFO << "Input channel name is current camera sensor channel";
1679 return;
1680 }
1681 status_.set_current_point_cloud_channel(channel_name);
1682 status_changed_ = true;
1683 }
1684}
1685
1686void HMIWorker::DeleteVehicleConfig(const std::string &vehicle_name) {
1687 if (vehicle_name.empty()) {
1688 return;
1689 }
1690 const std::string *vehicle_dir =
1691 FindOrNull(config_.vehicles(), vehicle_name);
1692 if (vehicle_dir == nullptr) {
1693 AERROR << "Unknow vehicle name" << vehicle_name;
1694 return;
1695 }
1696 {
1697 RLock rlock(status_mutex_);
1698 if (status_.current_vehicle() == vehicle_name) {
1699 AERROR << "The deleted vehicle profile is the one in use.";
1700 return;
1701 }
1702 }
1703 if (!cyber::common::DeleteFile(*vehicle_dir)) {
1704 AERROR << "Delete vehicle profile [" << vehicle_name << "] failed!";
1705 return;
1706 }
1707 if (!ReloadVehicles()) {
1708 AERROR << "Update vehicle profile [" << vehicle_name << "] failed!";
1709 return;
1710 }
1711}
1712
1713void HMIWorker::DeleteV2xConfig(const std::string &vehicle_name) {
1714 if (vehicle_name.empty()) {
1715 return;
1716 }
1717 const std::string *vehicle_dir =
1718 FindOrNull(config_.vehicles(), util::HMIUtil::TitleCase(vehicle_name));
1719 if (vehicle_dir == nullptr) {
1720 AERROR << "Unknow vehicle name " << vehicle_name;
1721 return;
1722 }
1723 const std::string v2x_dir = *vehicle_dir + "/v2x_conf";
1724 if (!cyber::common::PathExists(v2x_dir)) {
1725 AINFO << "The directory does not exist or the directory has been deleted";
1726 }
1727 if (!cyber::common::DeleteFile(v2x_dir)) {
1728 AERROR << "Delete v2x config [" << vehicle_name << "/v2x_conf] failed!";
1729 return;
1730 }
1731}
1732
1733bool HMIWorker::StartDataRecorder() {
1734 std::string start_cmd =
1735 "/apollo/scripts/record_bag.py --start --all --dreamview "
1736 "--default_name " +
1737 FLAGS_data_record_default_name;
1738 int ret = std::system(start_cmd.data());
1739 if (ret == 0) {
1740 auto *monitors = FuelMonitorManager::Instance()->GetCurrentMonitors();
1741 if (monitors != nullptr) {
1742 auto iter = monitors->find(FLAGS_data_collection_monitor_name);
1743 if (iter != monitors->end()) {
1744 auto *data_collection_monitor = iter->second.get();
1745 if (data_collection_monitor->IsEnabled() && record_count_ == 0) {
1746 data_collection_monitor->Restart();
1747 }
1748 }
1749 ++record_count_;
1750 }
1751 return true;
1752 } else {
1753 AERROR << "Failed to start the cyber_recorder process";
1754 return false;
1755 }
1756}
1757
1758bool HMIWorker::StopDataRecorder() {
1759 std::string stop_cmd = "/apollo/scripts/record_bag.py --stop";
1760 int ret = std::system(stop_cmd.data());
1761 if (ret == 0) {
1762 return true;
1763 } else {
1764 AERROR << "Failed to stop the cyber_recorder process";
1765 return false;
1766 }
1767}
1768
1769int HMIWorker::SaveDataRecorder(const std::string &new_name) {
1770 std::string data_record_default_path =
1771 std::string(cyber::common::GetEnv("HOME", "/home/apollo")) +
1772 "/.apollo/resources/records/" + FLAGS_data_record_default_name;
1773 if (!cyber::common::PathExists(data_record_default_path)) {
1774 AERROR << "Failed to save the record, the dreamview recording record does "
1775 "not exist, please record through dreamview.";
1776 return -2;
1777 }
1778 std::string save_cmd = "/apollo/scripts/record_bag.py --default_name " +
1779 FLAGS_data_record_default_name + " --rename " +
1780 new_name;
1781 int ret = std::system(save_cmd.data());
1782 if (ret == 0) {
1783 LoadRecords();
1784 return 1;
1785 } else {
1786 AERROR << "Failed to save the record, a file with the same name exists";
1787 return -1;
1788 }
1789}
1790
1791bool HMIWorker::DeleteDataRecorder() {
1792 std::string delete_cmd =
1793 "/apollo/scripts/record_bag.py --delete --default_name " +
1794 FLAGS_data_record_default_name;
1795 int ret = std::system(delete_cmd.data());
1796 if (ret == 0) {
1797 return true;
1798 } else {
1799 AERROR << "Failed to delete the record";
1800 return false;
1801 }
1802}
1803
1804void HMIWorker::ClearRecordInfo() {
1805 std::string last_record_id;
1806 {
1807 RLock rlock(status_mutex_);
1808 if (status_.current_operation() != HMIModeOperation::Record) {
1809 return;
1810 }
1811 last_record_id = status_.current_record_status().current_record_id();
1812 }
1813 if (!last_record_id.empty()) {
1814 StopRecordPlay(last_record_id);
1815 }
1816 // clear last channel msgs info for frontend after change record
1817 callback_api_("ClearDataHandlerConfChannelMsgs", {});
1818 WLock wlock(status_mutex_);
1819 status_.mutable_current_record_status()->clear_current_record_id();
1820 status_changed_ = true;
1821 return;
1822}
1823
1824void HMIWorker::ClearRtkRecordInfo() {
1825 std::string last_rtk_record_id;
1826 {
1827 RLock rlock(status_mutex_);
1828 if (status_.current_operation() != HMIModeOperation::Waypoint_Follow) {
1829 return;
1830 }
1831 last_rtk_record_id = status_.current_rtk_record_id();
1832 }
1833 if (!last_rtk_record_id.empty()) {
1834 StopPlayRtkRecorder();
1835 }
1836 {
1837 WLock wlock(status_mutex_);
1838 status_.set_current_rtk_record_id("");
1839 status_changed_ = true;
1840 }
1841 return;
1842}
1843
1844void HMIWorker::AddExpectedModules(const HMIAction& action) {
1845 WLock wlock(status_mutex_);
1846 int expected_modules = 1;
1847 if (action == HMIAction::SETUP_MODE) {
1848 expected_modules = status_.modules_size();
1849 }
1850 status_.set_expected_modules(status_.expected_modules() + expected_modules);
1851 status_changed_ = true;
1852}
1853
1854void HMIWorker::OnTimer(const double& overtime_time) {
1855 if (monitor_reader_ != nullptr) {
1856 auto delay_sec = monitor_reader_->GetDelaySec();
1857 if (delay_sec < 0 || delay_sec > overtime_time) {
1858 AERROR << "Running time error: monitor is not turned on!";
1859 {
1860 WLock wlock(status_mutex_);
1861 for (auto& iter : *status_.mutable_modules_lock()) {
1862 iter.second = false;
1863 }
1864 }
1865 }
1866 }
1867 {
1868 // When there is a problem with the module and it cannot be opened or
1869 // closed, unlock the loading lock state
1870 WLock wlock(status_mutex_);
1871 auto modules = status_.mutable_modules();
1872 auto modules_lock = status_.mutable_modules_lock();
1873 for (const auto &iter : current_mode_.modules()) {
1874 if (previous_modules_lock_[iter.first] && (*modules_lock)[iter.first] &&
1875 !isProcessRunning(iter.second.start_command())) {
1876 (*modules)[iter.first] = false;
1877 LockModule(iter.first, false);
1878 }
1879 previous_modules_lock_[iter.first] = (*modules_lock)[iter.first];
1880 }
1881 }
1882}
1883
1884void HMIWorker::LockModule(const std::string& module, const bool& lock_flag) {
1885 auto modules_lock = status_.mutable_modules_lock();
1886 (*modules_lock)[module] = lock_flag;
1887}
1888
1889bool HMIWorker::AddOrModifyObjectToDB(const std::string& key,
1890 const std::string& value) {
1891 return KVDB::Put(key, value);
1892}
1893
1894bool HMIWorker::DeleteObjectToDB(const std::string& key) {
1895 return KVDB::Delete(key);
1896}
1897
1898std::string HMIWorker::GetObjectFromDB(const std::string& key) {
1899 return KVDB::Get(key).value_or("");
1900}
1901
1902std::vector<std::pair<std::string, std::string>>
1903HMIWorker::GetTuplesWithTypeFromDB(const std::string& type) {
1904 return KVDB::GetWithStart(type);
1905}
1906
1907bool HMIWorker::StartTerminal() {
1908 return std::system(FLAGS_terminal_start_cmd.data()) == 0;
1909}
1910
1911void HMIWorker::GetRtkRecordPath(std::string *record_path) {
1912 CHECK_NOTNULL(record_path);
1913 *record_path = FLAGS_resource_rtk_record_path;
1914}
1915
1916bool HMIWorker::LoadRtkRecords() {
1917 {
1918 WLock wLock(status_mutex_);
1919 status_.clear_rtk_records();
1920 }
1921 std::string directory_path;
1922 GetRtkRecordPath(&directory_path);
1923 if (!cyber::common::PathExists(directory_path)) {
1924 AERROR << "Failed to find rtk records!";
1925 return false;
1926 }
1927 DIR *directory = opendir(directory_path.c_str());
1928 if (directory == nullptr) {
1929 AERROR << "Cannot open rtk record directory" << directory_path;
1930 return false;
1931 }
1932 struct dirent *file;
1933 std::map<std::string, double> new_records;
1934 while ((file = readdir(directory)) != nullptr) {
1935 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
1936 continue;
1937 }
1938 if (file->d_type == DT_DIR) {
1939 continue;
1940 }
1941 const std::string record_id = file->d_name;
1942 const int index = record_id.rfind(".csv");
1943 if (index != -1 && record_id[0] != '.') {
1944 const std::string local_record_resource = record_id.substr(0, index);
1945 {
1946 WLock wLock(status_mutex_);
1947 status_.add_rtk_records(local_record_resource);
1948 }
1949 }
1950 }
1951 closedir(directory);
1952 {
1953 WLock wlock(status_mutex_);
1954 status_changed_ = true;
1955 }
1956 return true;
1957}
1958
1959bool HMIWorker::StartRtkDataRecorder() {
1960 std::string start_cmd = "nohup /apollo/scripts/rtk_recorder.sh start &";
1961 int ret = std::system(start_cmd.data());
1962 if (ret == 0) {
1963 return true;
1964 } else {
1965 AERROR << "Failed to start the rtk_recorder process";
1966 return false;
1967 }
1968}
1969
1970bool HMIWorker::StopRtkDataRecorder() {
1971 std::string stop_cmd = "/apollo/scripts/rtk_recorder.sh stop";
1972 int ret = std::system(stop_cmd.data());
1973 if (ret == 9) {
1974 return true;
1975 } else {
1976 AERROR << "Failed to stop the rtk_recorder process";
1977 return false;
1978 }
1979}
1980
1981Json HMIWorker::StartPlayRtkRecorder() {
1982 Json result;
1983 if (!ChangeDrivingMode(Chassis::COMPLETE_AUTO_DRIVE)) {
1984 AERROR << "Failed to play rtk: Failed to enter auto drive.";
1985 result["error"] = "Failed to enter auto drive";
1986 result["isOk"] = false;
1987 return result;
1988 }
1989 std::string record_id;
1990 {
1991 RLock rlock(status_mutex_);
1992 record_id = status_.current_rtk_record_id();
1993 }
1994 std::string start_cmd =
1995 "nohup /apollo/scripts/rtk_player.sh start " + record_id + " &";
1996 int ret = std::system(start_cmd.data());
1997 if (ret == 0) {
1998 AINFO << "Start the rtk_recorder process Successful.";
1999 result["isOk"] = true;
2000 } else {
2001 AERROR << "Failed to play rtk: Failed to start the rtk_recorder process.";
2002 result["error"] = "Failed to start the rtk_recorder process";
2003 result["isOk"] = false;
2004 }
2005 return result;
2006}
2007
2008bool HMIWorker::StopPlayRtkRecorder() {
2009 std::string stop_cmd = "/apollo/scripts/rtk_player.sh stop";
2010 int ret = std::system(stop_cmd.data());
2011 if (ret == 9) {
2012 return true;
2013 } else {
2014 AERROR << "Failed to stop the rtk_recorder process";
2015 return false;
2016 }
2017}
2018
2019int HMIWorker::SaveRtkDataRecorder(const std::string &new_name) {
2020 std::string new_rtk_record_file =
2021 FLAGS_default_rtk_record_path + new_name + ".csv";
2022 if (cyber::common::PathExists(new_rtk_record_file)) {
2023 AERROR << "Failed to save the ret record, a file with the same name exists";
2024 return -1;
2025 }
2026 if (std::rename(FLAGS_default_rtk_record_file.data(),
2027 new_rtk_record_file.data()) == 0) {
2028 UpdateRtkRecordToStatus(new_name);
2029 return 1;
2030 } else {
2031 AERROR << "Failed to save the ret record, save command execution failed";
2032 return -3;
2033 }
2034}
2035
2036bool HMIWorker::DeleteRtkDataRecorder() {
2037 if (!cyber::common::PathExists(FLAGS_default_rtk_record_file)) {
2038 AERROR << "Failed to delete the ret record, file not exist";
2039 return false;
2040 }
2041 if (std::remove(FLAGS_default_rtk_record_file.data()) == 0) {
2042 return true;
2043 } else {
2044 AERROR << "Failed to delete the record, delete command execution failed";
2045 return false;
2046 }
2047 }
2048
2049void HMIWorker::ChangeRtkRecord(const std::string &record_id) {
2050 if (!StopPlayRtkRecorder()) {
2051 AWARN << "Warning to change rtk record: Failed to stop the rtk_recorder "
2052 "process.";
2053 }
2054 std::string last_record_id;
2055 {
2056 RLock rlock(status_mutex_);
2057 last_record_id = status_.current_rtk_record_id();
2058 }
2059 if (last_record_id == record_id) {
2060 AERROR << "Failed to change rtk record: rtk record is same!";
2061 return;
2062 }
2063 WLock wlock(status_mutex_);
2064 status_.set_current_rtk_record_id(record_id);
2065 status_changed_ = true;
2066 return;
2067}
2068
2069void HMIWorker::UpdateRtkRecordToStatus(const std::string &new_name) {
2070 WLock wlock(status_mutex_);
2071 status_.add_rtk_records(new_name);
2072 status_changed_ = true;
2073}
2074
2075void HMIWorker::ClearInvalidRecordStatus(const HMIModeOperation &operation) {
2076 HMIModeOperation last_operation;
2077 {
2078 RLock rlock(status_mutex_);
2079 last_operation = status_.current_operation();
2080 }
2081 if (operation == last_operation) {
2082 return;
2083 } else if (last_operation == HMIModeOperation::Waypoint_Follow) {
2084 StopRtkDataRecorder();
2085 DeleteRtkDataRecorder();
2086 } else if (operation == HMIModeOperation::Waypoint_Follow) {
2087 StopDataRecorder();
2088 DeleteDataRecorder();
2089 }
2090}
2091
2092bool HMIWorker::isProcessRunning(const std::string &process_name) {
2093 std::stringstream commandStream;
2094 commandStream << "pgrep -f " << process_name;
2095 std::string command = commandStream.str();
2096
2097 FILE *fp = popen(command.c_str(), "r");
2098 if (fp) {
2099 char result[128];
2100 if (fgets(result, sizeof(result), fp) != nullptr) {
2101 AINFO << process_name << " is running";
2102 pclose(fp);
2103 return true;
2104 } else {
2105 AINFO << process_name << " is not running";
2106 }
2107 pclose(fp);
2108 }
2109 return false;
2110}
2111
2112bool HMIWorker::PackageExist(const std::string& package_name) {
2113 std::string package_meta_info_path =
2114 FLAGS_apollo_package_meta_info_path_prefix + package_name +
2115 "/cyberfile.xml";
2116 AINFO << "package_meta_info_path: " << package_meta_info_path;
2117 return (cyber::common::PathExists(package_meta_info_path));
2118}
2119
2120std::string HMIWorker::GetCurrentModeDefaultLayout() {
2121 if (current_mode_.has_layout()) {
2122 const auto default_layout_json =
2124 "default_layout", current_mode_.layout());
2125 return default_layout_json["data"].dump();
2126 }
2127 AWARN << "There is no default layout for the current mode.";
2128 return "";
2129}
2130
2131void HMIWorker::LoadDvPluginPanelsJson() {
2132 plugin_panels_json_ = Json::array();
2133
2134 DIR *directory = opendir(FLAGS_dv_plugin_panels_path.c_str());
2135 if (!directory) {
2136 AERROR << "can not open: " << FLAGS_dv_plugin_panels_path;
2137 return;
2138 }
2139
2140 struct dirent *file;
2141 while ((file = readdir(directory)) != nullptr) {
2142 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
2143 continue;
2144 }
2145 std::string subdir_path = FLAGS_dv_plugin_panels_path + "/" + file->d_name;
2146 if (file->d_type == DT_DIR) {
2147 std::string file_path = subdir_path + "/conf.json";
2148
2149 std::ifstream ifs(file_path);
2150 if (!ifs.is_open()) {
2151 AERROR << "can not open: " << file_path;
2152 continue;
2153 }
2154
2155 Json conf_json;
2156 ifs >> conf_json;
2157 ifs.close();
2158 plugin_panels_json_.push_back(conf_json);
2159 }
2160 }
2161 closedir(directory);
2162}
2163
2164std::string HMIWorker::GetDvPluginPanelsJsonStr() {
2165 return plugin_panels_json_.empty() ? "" : plugin_panels_json_.dump();
2166}
2167
2168} // namespace dreamview
2169} // namespace apollo
Lightweight key-value database to store system-wide parameters.
Definition kv_db.h:38
static nlohmann::json ProtoToTypedJson(const std::string &json_type, const google::protobuf::Message &proto)
Convert proto to a json string.
Definition json_util.cc:37
a singleton clock that can be used to get the current timestamp.
Definition clock.h:39
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
Node is the fundamental building block of Cyber RT.
Definition node.h:44
#define ACHECK(cond)
Definition log.h:80
#define AERROR
Definition log.h:44
#define AERROR_IF(cond)
Definition log.h:74
#define AFATAL
Definition log.h:45
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
Some map util functions.
Some string util functions.
nlohmann::json Json
size_t MessageFingerprint(const google::protobuf::Message &message)
bool LoadConfig(const std::string &relative_path, T *config)
Definition file.h:265
boost::shared_lock< boost::shared_mutex > RLock
boost::unique_lock< boost::shared_mutex > WLock
const std::string start_cmd
Definition teleop.cc:53
const std::string stop_cmd
Definition teleop.cc:54
class register implement
DEFINE_string(cyber_recorder_play_command, "cyber_recorder play -p 1 -f ", "Cyber recorder play command")