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