Apollo 10.0
自动驾驶开放平台
hmi.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 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 <string>
20#include <vector>
21#include <utility>
22
23#include "google/protobuf/util/json_util.h"
24
25#include "modules/dreamview/proto/preprocess_table.pb.h"
26
27#include "cyber/common/file.h"
33
34namespace apollo {
35namespace dreamview {
36
39using google::protobuf::util::JsonStringToMessage;
41
42HMI::HMI(WebSocketHandler* websocket, MapService* map_service,
43 WebSocketHandler* hmi_websocket)
44 : monitor_log_buffer_(apollo::common::monitor::MonitorMessageItem::HMI),
45 hmi_worker_(new HMIWorker(monitor_log_buffer_)),
46 websocket_(websocket),
47 map_service_(map_service),
48 hmi_ws_(hmi_websocket) {
49 if (websocket_) {
50 RegisterDBMessageHandlers();
51 RegisterFrontendConfMessageHandlers();
52 RegisterMessageHandlers();
53 }
54}
55
56void HMI::StartStream(const double& time_interval_ms,
57 const std::string& channel_name,
58 nlohmann::json* subscribe_param) {
59 AINFO << "Start HMIStatus updater timer with data sending frequency: "
60 << time_interval_ms;
61 time_interval_ms_ = time_interval_ms;
62 if (time_interval_ms_ > 0) {
63 timer_.reset(new cyber::Timer(
64 time_interval_ms, [this]() { this->OnTimer(); }, false));
65 timer_->Start();
66 } else {
67 this->OnTimer();
68 }
69}
70
71void HMI::Start(DvCallback callback_api) { hmi_worker_->Start(callback_api); }
72
73void HMI::Stop() { hmi_worker_->Stop(); }
74
75void HMI::StopStream(const std::string& channel_name) {
76 AINFO << "HMIStatus updater timer has been stopped";
77 if (timer_) {
78 timer_->Stop();
79 }
80}
81
82void HMI::RegisterDBMessageHandlers() {
83 websocket_->RegisterMessageHandler(
84 "AddOrModifyObjectToDB",
85 [this](const Json& json, WebSocketHandler::Connection* conn) {
86 Json response;
87 response["action"] = "response";
88 std::string request_id;
89 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
90 AERROR
91 << "Failed to add or modify object to DB: requestId not found.";
92 response["data"]["info"]["code"] = -1;
93 response["data"]["info"]["message"] = "Miss requestId";
94 websocket_->SendData(conn, response.dump());
95 return;
96 }
97 response["data"]["requestId"] = request_id;
98 std::string key, value;
99 if (!JsonUtil::GetStringByPath(json, "data.info.key", &key)) {
100 AERROR << "Failed to add or modify object to DB: key not found.";
101 response["data"]["info"]["code"] = -1;
102 response["data"]["info"]["message"] = "Miss key";
103 websocket_->SendData(conn, response.dump());
104 return;
105 } else if (!JsonUtil::GetStringByPath(json, "data.info.value",
106 &value)) {
107 AERROR << "Failed to add or modify object to DB: value not found.";
108 response["data"]["info"]["code"] = -1;
109 response["data"]["info"]["message"] = "Miss value";
110 websocket_->SendData(conn, response.dump());
111 return;
112 }
113 bool ret = hmi_worker_->AddOrModifyObjectToDB(key, value);
114 if (ret) {
115 response["data"]["info"]["code"] = 0;
116 response["data"]["info"]["message"] = "Success";
117 } else {
118 response["data"]["info"]["code"] = -1;
119 response["data"]["info"]["message"] =
120 "Failed to add or modify object to DB";
121 }
122 websocket_->SendData(conn, response.dump());
123 });
124
125 websocket_->RegisterMessageHandler(
126 "GetObjectFromDB",
127 [this](const Json& json, WebSocketHandler::Connection* conn) {
128 Json response;
129 response["action"] = "response";
130 std::string request_id;
131 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
132 AERROR << "Failed to get object from DB: requestId not found.";
133 response["data"]["info"]["code"] = -1;
134 response["data"]["info"]["message"] = "Miss requestId";
135 websocket_->SendData(conn, response.dump());
136 return;
137 }
138 response["data"]["requestId"] = request_id;
139 std::string key, value;
140 if (!JsonUtil::GetStringByPath(json, "data.info.key", &key)) {
141 AERROR << "Failed to get object from DB: key not found.";
142 response["data"]["info"]["code"] = -1;
143 response["data"]["info"]["message"] = "Miss key";
144 websocket_->SendData(conn, response.dump());
145 return;
146 }
147 std::string ret = hmi_worker_->GetObjectFromDB(key);
148 response["data"]["info"]["data"] = ret;
149 response["data"]["info"]["code"] = 0;
150 response["data"]["info"]["message"] = "Success";
151 websocket_->SendData(conn, response.dump());
152 });
153
154 websocket_->RegisterMessageHandler(
155 "DeleteObjectToDB",
156 [this](const Json& json, WebSocketHandler::Connection* conn) {
157 Json response;
158 response["action"] = "response";
159 std::string request_id;
160 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
161 AERROR << "Failed to delete object to DB: requestId not found.";
162 response["data"]["info"]["code"] = -1;
163 response["data"]["info"]["message"] = "Miss requestId";
164 websocket_->SendData(conn, response.dump());
165 return;
166 }
167 response["data"]["requestId"] = request_id;
168 std::string key, value;
169 if (!JsonUtil::GetStringByPath(json, "data.info.key", &key)) {
170 AERROR << "Failed to delete object to DB: key not found.";
171 response["data"]["info"]["code"] = -1;
172 response["data"]["info"]["message"] = "Miss key";
173 websocket_->SendData(conn, response.dump());
174 return;
175 }
176 bool ret = hmi_worker_->DeleteObjectToDB(key);
177 if (ret) {
178 response["data"]["info"]["code"] = 0;
179 response["data"]["info"]["message"] = "Success";
180 } else {
181 response["data"]["info"]["code"] = -1;
182 response["data"]["info"]["message"] = "Failed to delete object to DB";
183 }
184 websocket_->SendData(conn, response.dump());
185 });
186
187 websocket_->RegisterMessageHandler(
188 "GetTuplesWithTypeFromDB",
189 [this](const Json& json, WebSocketHandler::Connection* conn) {
190 Json response;
191 response["action"] = "response";
192 std::string request_id;
193 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
194 AERROR
195 << "Failed to get tuples with type from DB: requestId not found.";
196 response["data"]["info"]["code"] = -1;
197 response["data"]["info"]["message"] = "Miss requestId";
198 websocket_->SendData(conn, response.dump());
199 return;
200 }
201 response["data"]["requestId"] = request_id;
202 std::string type;
203 if (!JsonUtil::GetStringByPath(json, "data.info.type", &type)) {
204 AERROR << "Failed to get tuples with type from DB: type not found.";
205 response["data"]["info"]["code"] = -1;
206 response["data"]["info"]["message"] = "Miss type";
207 websocket_->SendData(conn, response.dump());
208 return;
209 }
210 auto ret = hmi_worker_->GetTuplesWithTypeFromDB(type);
211 Json tuples = Json::array();
212 for (const auto& item : ret) {
213 Json tuple;
214 tuple["key"] = item.first;
215 tuple["value"] = item.second;
216 tuples.push_back(tuple);
217 }
218 response["data"]["info"]["data"] = tuples;
219 response["data"]["info"]["code"] = 0;
220 response["data"]["info"]["message"] = "Success";
221 websocket_->SendData(conn, response.dump());
222 });
223}
224
225void HMI::RegisterFrontendConfMessageHandlers() {
226 websocket_->RegisterMessageHandler(
227 "GetCurrentLayout",
228 [this](const Json& json, WebSocketHandler::Connection* conn) {
229 Json response;
230 response["action"] = "response";
231 std::string request_id;
232 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
233 AERROR
234 << "Failed to add or modify object to DB: requestId not found.";
235 response["data"]["info"]["code"] = -1;
236 response["data"]["info"]["message"] = "Miss requestId";
237 websocket_->SendData(conn, response.dump());
238 return;
239 }
240 response["data"]["requestId"] = request_id;
241 const auto current_mode = hmi_worker_->GetStatus().current_mode();
242 std::string current_layout = hmi_worker_->GetObjectFromDB(current_mode);
243 // If not have current layout, return default layout.
244 if (current_layout.empty()) {
245 AINFO << "There is no current layout, returning the default.";
246 current_layout = hmi_worker_->GetCurrentModeDefaultLayout();
247 }
248 response["data"]["info"]["data"] = current_layout;
249 response["data"]["info"]["code"] = 0;
250 response["data"]["info"]["message"] = "Success";
251 websocket_->SendData(conn, response.dump());
252 });
253 websocket_->RegisterMessageHandler(
254 "GetDefaultLayout",
255 [this](const Json& json, WebSocketHandler::Connection* conn) {
256 Json response;
257 response["action"] = "response";
258 std::string request_id;
259 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
260 AERROR
261 << "Failed to add or modify object to DB: requestId not found.";
262 response["data"]["info"]["code"] = -1;
263 response["data"]["info"]["message"] = "Miss requestId";
264 websocket_->SendData(conn, response.dump());
265 return;
266 }
267 response["data"]["requestId"] = request_id;
268 std::string default_layout = hmi_worker_->GetCurrentModeDefaultLayout();
269 response["data"]["info"]["data"] = default_layout;
270 response["data"]["info"]["code"] = 0;
271 response["data"]["info"]["message"] = "Success";
272 websocket_->SendData(conn, response.dump());
273 });
274 websocket_->RegisterMessageHandler(
275 "GetDvPluginPanelsJson",
276 [this](const Json& json, WebSocketHandler::Connection* conn) {
277 Json response;
278 response["action"] = "response";
279 std::string request_id;
280 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
281 AERROR << "Failed to get dv plugin panels json: requestId not found.";
282 response["data"]["info"]["code"] = -1;
283 response["data"]["info"]["message"] = "Miss requestId";
284 websocket_->SendData(conn, response.dump());
285 return;
286 }
287 response["data"]["requestId"] = request_id;
288 std::string plugin_panels_json_str =
289 hmi_worker_->GetDvPluginPanelsJsonStr();
290 response["data"]["info"]["data"] = plugin_panels_json_str;
291 response["data"]["info"]["code"] = 0;
292 response["data"]["info"]["message"] = "Success";
293 websocket_->SendData(conn, response.dump());
294 });
295}
296
297void HMI::RegisterMessageHandlers() {
298 // Send current status and vehicle param to newly joined client.
299 // websocket_->RegisterConnectionReadyHandler(
300 // [this](WebSocketHandler::Connection* conn) {
301 // // SendStatus(conn);
302 // SendVehicleParam(conn);
303 // });
304
305 websocket_->RegisterMessageHandler(
306 "HMIAction",
307 [this](const Json& json, WebSocketHandler::Connection* conn) {
308 // Run HMIWorker::Trigger(action) if json is {action: "<action>"}
309 // Run HMIWorker::Trigger(action, value) if "value" field is provided.
310
311 // response is used for interfaces that require a reply
312 Json response;
313 response["action"] = "response";
314 std::string request_id;
315 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
316 AERROR << "Failed to start hmi action: requestId not found.";
317 response["data"]["info"]["code"] = -1;
318 response["data"]["info"]["message"] = "Miss requestId";
319 websocket_->SendData(conn, response.dump());
320 return;
321 }
322 response["data"]["requestId"] = request_id;
323
324 std::string action;
325 if (!JsonUtil::GetStringByPath(json, "data.info.action", &action)) {
326 AERROR << "Truncated HMIAction request.";
327 return;
328 }
329 HMIAction hmi_action;
330 if (!HMIAction_Parse(action, &hmi_action)) {
331 AERROR << "Invalid HMIAction string: " << action;
332 return;
333 }
334 bool is_ok = false;
335 std::string value;
336 if (JsonUtil::GetStringByPath(json, "data.info.value", &value)) {
337 is_ok = hmi_worker_->Trigger(hmi_action, value);
338 } else {
339 is_ok = hmi_worker_->Trigger(hmi_action);
340 }
341
342 // Extra works for current Dreamview.
343 if (hmi_action == HMIAction::CHANGE_VEHICLE) {
344 // Reload lidar params for point cloud service.
345 SendVehicleParam();
346 } else if (hmi_action == HMIAction::CHANGE_MAP) {
347 response["data"]["info"]["data"]["isOk"] = is_ok;
348 response["data"]["info"]["code"] = 0;
349 response["data"]["info"]["message"] =
350 is_ok ? "Success" : "Failed to change map";
351 websocket_->SendData(conn, response.dump());
352 } else if (hmi_action == HMIAction::CHANGE_OPERATION ||
353 hmi_action == HMIAction::CHANGE_MODE) {
354 response["data"]["info"]["data"]["isOk"] = true;
355 response["data"]["info"]["code"] = 0;
356 response["data"]["info"]["message"] = "Success";
357 websocket_->SendData(conn, response.dump());
358 }
359 });
360
361 // HMI client asks for adding new AudioEvent.
362 websocket_->RegisterMessageHandler(
363 "SubmitAudioEvent",
364 [this](const Json& json, WebSocketHandler::Connection* conn) {
365 // json should contain event_time_ms, obstacle_id, audio_type,
366 // moving_result, audio_direction and is_siren_on.
367 uint64_t event_time_ms;
368 int obstacle_id;
369 int audio_type;
370 int moving_result;
371 int audio_direction;
372 bool is_siren_on;
373 if (JsonUtil::GetNumber(json, "event_time_ms", &event_time_ms) &&
374 JsonUtil::GetNumber(json, "obstacle_id", &obstacle_id) &&
375 JsonUtil::GetNumber(json, "audio_type", &audio_type) &&
376 JsonUtil::GetNumber(json, "moving_result", &moving_result) &&
377 JsonUtil::GetNumber(json, "audio_direction", &audio_direction) &&
378 JsonUtil::GetBoolean(json, "is_siren_on", &is_siren_on)) {
379 hmi_worker_->SubmitAudioEvent(event_time_ms, obstacle_id, audio_type,
380 moving_result, audio_direction,
381 is_siren_on);
382 monitor_log_buffer_.INFO("Audio event added.");
383 } else {
384 AERROR << "Truncated SubmitAudioEvent request.";
385 monitor_log_buffer_.WARN("Failed to submit an audio event.");
386 }
387 });
388
389 // HMI client asks for adding new DriveEvent.
390 websocket_->RegisterMessageHandler(
391 "SubmitDriveEvent",
392 [this](const Json& json, WebSocketHandler::Connection* conn) {
393 // json should contain event_time_ms and event_msg.
394 uint64_t event_time_ms;
395 std::string event_msg;
396 std::vector<std::string> event_types;
397 bool is_reportable;
398 if (JsonUtil::GetNumber(json, "event_time_ms", &event_time_ms) &&
399 JsonUtil::GetString(json, "event_msg", &event_msg) &&
400 JsonUtil::GetStringVector(json, "event_type", &event_types) &&
401 JsonUtil::GetBoolean(json, "is_reportable", &is_reportable)) {
402 hmi_worker_->SubmitDriveEvent(event_time_ms, event_msg, event_types,
403 is_reportable);
404 monitor_log_buffer_.INFO("Drive event added.");
405 } else {
406 AERROR << "Truncated SubmitDriveEvent request.";
407 monitor_log_buffer_.WARN("Failed to submit a drive event.");
408 }
409 });
410
411 websocket_->RegisterMessageHandler(
412 "StartPlayRecorder",
413 [this](const Json& json, WebSocketHandler::Connection* conn) {
414 std::string request_id;
415 Json response({});
416 response["action"] = "response";
417 Json info({});
418 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
419 // 失败情况
420 info["code"] = -1;
421 info["message"] = "Miss requestId";
422 AERROR << "Miss required field requestId to execute play recorder "
423 "action.";
424
425 } else {
426 bool exec_action_result = hmi_worker_->RePlayRecord();
427 info["code"] = exec_action_result ? 0 : -1;
428 if (!exec_action_result) {
429 info["message"] = "Failed to start play recorder";
430 }
431 }
432 response["data"]["info"] = info;
433 if (!request_id.empty()) {
434 response["data"]["requestId"] = request_id;
435 }
436 websocket_->SendData(conn, response.dump());
437 });
438
439 websocket_->RegisterMessageHandler(
440 "ResetRecordProgress",
441 [this](const Json& json, WebSocketHandler::Connection* conn) {
442 std::string request_id;
443 std::string progress_str;
444 Json response({});
445 response["action"] = "response";
446 Json info({});
447 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
448 info["code"] = -1;
449 info["message"] = "Miss requestId";
450 AERROR << "Miss required field requestId to execute play recorder "
451 "action.";
452
453 } else if (!JsonUtil::GetStringByPath(json, "data.info.progress",
454 &progress_str)) {
455 info["code"] = -1;
456 info["message"] = "Miss progress";
457 AERROR << "Miss required field progress to reset record progress.";
458 } else {
459 double progress;
460 bool valid_progress = true;
461 try {
462 progress = std::stod(progress_str);
463 AINFO << "Progress: " << progress;
464 } catch (const std::invalid_argument& ia) {
465 AERROR << "Invalid argument progress: " << progress_str;
466 valid_progress = false;
467 } catch (const std::out_of_range& e) {
468 AERROR << "Argument is out of range: " << progress_str;
469 valid_progress = false;
470 }
471 if (valid_progress) {
472 bool result = hmi_worker_->ResetRecordProgress(progress);
473 info["code"] = result ? 0 : -1;
474 if (!result) {
475 info["message"] = "Failed to start play recorder";
476 }
477 } else {
478 info["code"] = -1;
479 info["message"] = "Failed to get proress value";
480 }
481 }
482 response["data"]["info"] = info;
483 if (!request_id.empty()) {
484 response["data"]["requestId"] = request_id;
485 }
486 websocket_->SendData(conn, response.dump());
487 });
488
489 websocket_->RegisterMessageHandler(
490 "PlayRecorderAction",
491 [this](const Json& json, WebSocketHandler::Connection* conn) {
492 std::string request_id;
493 std::string action_type;
494 double progress;
495 Json response({});
496 response["action"] = "response";
497 Json info({});
498 if (!JsonUtil::GetStringByPath(json, "data.info.actionType",
499 &action_type)) {
500 info["code"] = -1;
501 info["message"] = "Error param";
502 AERROR << "Failed to get param to execute play recorder action.";
503 } else if (!JsonUtil::GetStringByPath(json, "data.requestId",
504 &request_id)) {
505 // 失败情况
506 info["code"] = -1;
507 info["message"] = "Miss requestId";
508 AERROR << "Miss required field requestId to execute play recorder "
509 "action.";
510
511 } else if (action_type.compare("continue") == 0 &&
512 !JsonUtil::GetNumberByPath(json, "data.info.progress",
513 &progress)) {
514 AERROR << "Miss required field progress to continue play record!";
515 info["code"] = -1;
516 info["message"] = "Miss progress";
517 } else {
518 bool exec_action_result =
519 hmi_worker_->handlePlayRecordProcess(action_type);
520 info["code"] = exec_action_result ? 0 : -1;
521 if (!exec_action_result) {
522 info["message"] =
523 "Failed to execute play recorder action: " + action_type;
524 }
525 }
526 response["data"]["info"] = info;
527 if (!request_id.empty()) {
528 response["data"]["requestId"] = request_id;
529 }
530 websocket_->SendData(conn, response.dump());
531 });
532
533 websocket_->RegisterMessageHandler(
534 "StartDataRecorder",
535 [this](const Json& json, WebSocketHandler::Connection* conn) {
536 Json response;
537 response["action"] = "response";
538 std::string request_id;
539 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
540 AERROR << "Failed to start data recorder: requestId not found.";
541 response["data"]["info"]["code"] = -1;
542 response["data"]["info"]["message"] = "Miss requestId";
543 websocket_->SendData(conn, response.dump());
544 return;
545 }
546 response["data"]["requestId"] = request_id;
547 bool ret;
548 if (hmi_worker_->GetStatus().current_operation() ==
549 HMIModeOperation::Waypoint_Follow) {
550 ret = hmi_worker_->StartRtkDataRecorder();
551 } else {
552 ret = hmi_worker_->StartDataRecorder();
553 }
554 if (ret) {
555 response["data"]["info"]["code"] = 0;
556 response["data"]["info"]["message"] = "Success";
557 } else {
558 response["data"]["info"]["code"] = -1;
559 response["data"]["info"]["message"] =
560 "Failed to start data recorder:Failed to start the "
561 "cyber_recorder process";
562 }
563 websocket_->SendData(conn, response.dump());
564 });
565
566 websocket_->RegisterMessageHandler(
567 "StopDataRecorder",
568 [this](const Json& json, WebSocketHandler::Connection* conn) {
569 Json response;
570 response["action"] = "response";
571 std::string request_id;
572 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
573 AERROR << "Failed to start data recorder: requestId not found.";
574 response["data"]["info"]["code"] = -1;
575 response["data"]["info"]["message"] = "Miss requestId";
576 websocket_->SendData(conn, response.dump());
577 return;
578 }
579 response["data"]["requestId"] = request_id;
580 bool ret;
581 if (hmi_worker_->GetStatus().current_operation() ==
582 HMIModeOperation::Waypoint_Follow) {
583 ret = hmi_worker_->StopRtkDataRecorder();
584 } else {
585 ret = hmi_worker_->StopDataRecorder();
586 }
587 if (ret) {
588 response["data"]["info"]["code"] = 0;
589 response["data"]["info"]["message"] = "Success";
590 } else {
591 response["data"]["info"]["code"] = -1;
592 response["data"]["info"]["message"] =
593 "Failed to stop data recorder: failed to stop the cyber_recorder "
594 "process";
595 }
596 websocket_->SendData(conn, response.dump());
597 });
598
599 websocket_->RegisterMessageHandler(
600 "StartPlayRtkRecorder",
601 [this](const Json& json, WebSocketHandler::Connection* conn) {
602 Json response;
603 response["action"] = "response";
604 std::string request_id;
605 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
606 AERROR << "Failed to start data recorder: requestId not found.";
607 response["data"]["info"]["code"] = -1;
608 response["data"]["info"]["message"] = "Miss requestId";
609 websocket_->SendData(conn, response.dump());
610 return;
611 }
612 response["data"]["requestId"] = request_id;
613 if (hmi_worker_->GetStatus().current_operation() !=
614 HMIModeOperation::Waypoint_Follow) {
615 response["data"]["info"]["code"] = -1;
616 response["data"]["info"]["message"] =
617 "The current operation is not a Waypoint_ Follow";
618 }
619 Json result = hmi_worker_->StartPlayRtkRecorder();
620 response["data"]["info"]["code"] = result["isOk"] ? 0 : -1;
621 response["data"]["info"]["message"] =
622 result["isOk"] ? "Success" : result["error"];
623 websocket_->SendData(conn, response.dump());
624 });
625
626 websocket_->RegisterMessageHandler(
627 "StopPlayRtkRecorder",
628 [this](const Json& json, WebSocketHandler::Connection* conn) {
629 Json response;
630 response["action"] = "response";
631 std::string request_id;
632 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
633 AERROR << "Failed to start data recorder: requestId not found.";
634 response["data"]["info"]["code"] = -1;
635 response["data"]["info"]["message"] = "Miss requestId";
636 websocket_->SendData(conn, response.dump());
637 return;
638 }
639 response["data"]["requestId"] = request_id;
640 if (hmi_worker_->GetStatus().current_operation() !=
641 HMIModeOperation::Waypoint_Follow) {
642 response["data"]["info"]["code"] = -1;
643 response["data"]["info"]["message"] =
644 "The current operation is not a Waypoint_ Follow";
645 }
646 bool ret = hmi_worker_->StopPlayRtkRecorder();
647 if (ret) {
648 response["data"]["info"]["code"] = 0;
649 response["data"]["info"]["message"] = "Success";
650 } else {
651 response["data"]["info"]["code"] = -1;
652 response["data"]["info"]["message"] =
653 "Failed to stop play data recorder process";
654 }
655 websocket_->SendData(conn, response.dump());
656 });
657
658 websocket_->RegisterMessageHandler(
659 "SaveDataRecorder",
660 [this](const Json& json, WebSocketHandler::Connection* conn) {
661 Json response;
662 response["action"] = "response";
663 std::string request_id, new_name;
664 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
665 AERROR << "Failed to save record: requestId not found.";
666 response["data"]["info"]["code"] = -1;
667 response["data"]["info"]["message"] = "Miss requestId";
668 websocket_->SendData(conn, response.dump());
669 return;
670 } else if (!JsonUtil::GetStringByPath(json, "data.info.newName",
671 &new_name)) {
672 AERROR << "Failed to save record: newName not found.";
673 response["data"]["info"]["code"] = -1;
674 response["data"]["info"]["message"] = "Miss newName";
675 websocket_->SendData(conn, response.dump());
676 return;
677 }
678 response["data"]["requestId"] = request_id;
679 int ret;
680 if (hmi_worker_->GetStatus().current_operation() ==
681 HMIModeOperation::Waypoint_Follow) {
682 ret = hmi_worker_->SaveRtkDataRecorder(new_name);
683 } else {
684 ret = hmi_worker_->SaveDataRecorder(new_name);
685 }
686 if (ret == 1) {
687 response["data"]["info"]["code"] = 0;
688 response["data"]["info"]["message"] = "Success";
689 } else if (ret == -1) {
690 response["data"]["info"]["code"] = -1;
691 response["data"]["info"]["message"] =
692 "Failed to save record: a file with the same name exists";
693 } else if (ret == -2) {
694 response["data"]["info"]["code"] = -1;
695 response["data"]["info"]["message"] =
696 "Failed to save the record: the dreamview recording record does "
697 "not exist, please record through dreamview";
698 } else {
699 response["data"]["info"]["code"] = -1;
700 response["data"]["info"]["message"] =
701 "Failed to save record: please try again or check whether your "
702 "record is legal";
703 }
704 websocket_->SendData(conn, response.dump());
705 });
706
707 websocket_->RegisterMessageHandler(
708 "DeleteDataRecorder",
709 [this](const Json& json, WebSocketHandler::Connection* conn) {
710 Json response;
711 response["action"] = "response";
712 std::string request_id;
713 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
714 AERROR << "Failed to start data recorder: requestId not found.";
715 response["data"]["info"]["code"] = -1;
716 response["data"]["info"]["message"] = "Miss requestId";
717 websocket_->SendData(conn, response.dump());
718 return;
719 }
720 response["data"]["requestId"] = request_id;
721 bool ret;
722 if (hmi_worker_->GetStatus().current_operation() ==
723 HMIModeOperation::Waypoint_Follow) {
724 ret = hmi_worker_->DeleteRtkDataRecorder();
725 } else {
726 ret = hmi_worker_->DeleteDataRecorder();
727 }
728 if (ret) {
729 response["data"]["info"]["code"] = 0;
730 response["data"]["info"]["message"] = "Success";
731 } else {
732 response["data"]["info"]["code"] = -1;
733 response["data"]["info"]["message"] = "Failed to delete the record";
734 }
735 websocket_->SendData(conn, response.dump());
736 });
737
738 // To speed up the preloading process, fetching from hmi is relatively slow.
739 websocket_->RegisterMessageHandler(
740 "GetInitData",
741 [this](const Json& json, WebSocketHandler::Connection* conn) {
742 Json response;
743 response["action"] = "response";
744 std::string request_id;
745 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
746 AERROR << "Failed to get current mode: requestId not found.";
747 response["data"]["info"]["code"] = -1;
748 response["data"]["info"]["message"] = "Miss requestId";
749 websocket_->SendData(conn, response.dump());
750 return;
751 }
752 response["data"]["requestId"] = request_id;
753 std::string current_mode = hmi_worker_->GetStatus().current_mode();
754 auto current_operation = hmi_worker_->GetStatus().current_operation();
755 response["data"]["info"]["data"]["currentMode"] = current_mode;
756 response["data"]["info"]["data"]["currentOperation"] =
757 HMIModeOperation_Name(current_operation);
758 response["data"]["info"]["code"] = 0;
759 response["data"]["info"]["message"] = "Success";
760 websocket_->SendData(conn, response.dump());
761 });
762
763 websocket_->RegisterMessageHandler(
764 "StartTerminal",
765 [this](const Json& json, WebSocketHandler::Connection* conn) {
766 Json response;
767 response["action"] = "response";
768 std::string request_id;
769 if (!JsonUtil::GetStringByPath(json, "data.requestId", &request_id)) {
770 AERROR << "Failed to start terminal: requestId not found.";
771 response["data"]["info"]["code"] = -1;
772 response["data"]["info"]["message"] = "Miss requestId";
773 websocket_->SendData(conn, response.dump());
774 return;
775 }
776 response["data"]["requestId"] = request_id;
777 bool ret = hmi_worker_->StartTerminal();
778 if (ret) {
779 response["data"]["info"]["code"] = 0;
780 response["data"]["info"]["message"] = "Success";
781 } else {
782 response["data"]["info"]["code"] = -1;
783 response["data"]["info"]["message"] = "Failed to start terminal";
784 }
785 websocket_->SendData(conn, response.dump());
786 });
787}
788
789void HMI::SendVehicleParam(WebSocketHandler::Connection* conn) {
790 if (websocket_ == nullptr) {
791 return;
792 }
793
794 const auto& vehicle_param =
796 const std::string json_str =
797 JsonUtil::ProtoToTypedJson("VehicleParam", vehicle_param).dump();
798 if (conn != nullptr) {
799 websocket_->SendData(conn, json_str);
800 } else {
801 websocket_->BroadcastData(json_str);
802 }
803}
804
805void HMI::OnTimer(const std::string& channel_name) { PublishMessage(); }
806
807void HMI::PublishMessage(const std::string& channel_name) {
808 StreamData response;
809 response.set_action("stream");
810 response.set_data_name("hmistatus");
811 std::string hmi_status_str;
812 hmi_worker_->GetStatus().SerializeToString(&hmi_status_str);
813 std::vector<uint8_t> byte_data(hmi_status_str.begin(), hmi_status_str.end());
814 response.set_data(&(byte_data[0]), byte_data.size());
815 response.set_type("hmistatus");
816 std::string response_str;
817 response.SerializeToString(&response_str);
818 hmi_ws_->BroadcastBinaryData(response_str);
819}
820
821bool HMI::UpdateDynamicModelToStatus(const std::string& dynamic_model_name) {
822 return hmi_worker_->UpdateDynamicModelToStatus(dynamic_model_name);
823}
824
825bool HMI::UpdateMapToStatus(const std::string& map_name) {
826 return hmi_worker_->UpdateMapToStatus(map_name);
827}
828
829bool HMI::UpdateRecordToStatus() { return hmi_worker_->LoadRecords(); }
830
831bool HMI::UpdateVehicleToStatus() { return hmi_worker_->ReloadVehicles(); }
832
833bool HMI::UpdateCameraChannelToStatus(const std::string& channel_name) {
834 hmi_worker_->UpdateCameraSensorChannelToStatus(channel_name);
835 return true;
836}
837
838bool HMI::UpdatePointChannelToStatus(const std::string& channel_name) {
839 hmi_worker_->UpdatePointCloudChannelToStatus(channel_name);
840 return true;
841}
842
843bool HMI::isProcessRunning(const std::string& process_name) {
844 return hmi_worker_->isProcessRunning(process_name);
845}
846
847} // namespace dreamview
848} // namespace apollo
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
static bool GetNumber(const nlohmann::json &json, const std::string &key, T *value)
Get a number value from the given json[key].
Definition json_util.h:59
static bool GetStringVector(const nlohmann::json &json, const std::string &key, std::vector< std::string > *value)
Get a string vector from the given json[key].
Definition json_util.cc:109
static bool GetStringByPath(const nlohmann::json &json, const std::string &path, std::string *value)
Get a string value from the given json and path.
Definition json_util.cc:97
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
static bool GetBoolean(const nlohmann::json &json, const std::string &key, bool *value)
Get a boolean value from the given json[key].
Definition json_util.cc:137
static bool GetNumberByPath(const nlohmann::json &json, const std::string &path, T *value)
Get a number value from the given json and path.
Definition json_util.h:120
static bool GetString(const nlohmann::json &json, const std::string &key, std::string *value)
Get a string value from the given json[key].
Definition json_util.cc:58
Used to perform oneshot or periodic timing tasks
Definition timer.h:71
void StopStream(const std::string &channel_name="") override
Stop data flow.
Definition hmi.cc:75
HMI(WebSocketHandler *websocket, MapService *map_service)
Definition hmi.cc:42
void OnTimer(const std::string &channel_name="")
Definition hmi.cc:805
void StartStream(const double &time_interval_ms, const std::string &channel_name="", nlohmann::json *subscribe_param=nullptr) override
Start data flow.
Definition hmi.cc:56
bool UpdateMapToStatus(const std::string &map_name="")
Definition hmi.cc:825
bool UpdateDynamicModelToStatus(const std::string &dynamic_model_name)
Definition hmi.cc:243
bool UpdatePointChannelToStatus(const std::string &channel_name)
Definition hmi.cc:256
bool UpdateRecordToStatus()
Definition hmi.cc:247
bool UpdateCameraChannelToStatus(const std::string &channel_name)
Definition hmi.cc:251
void PublishMessage(const std::string &channel_name="") override
Publish Message to dreamview frontend.
Definition hmi.cc:807
bool isProcessRunning(const std::string &process_name)
Definition hmi.cc:843
void Start(DvCallback callback_api)
Definition hmi.cc:52
bool UpdateVehicleToStatus()
Definition hmi.cc:249
The WebSocketHandler, built on top of CivetWebSocketHandler, is a websocket handler that handles diff...
bool BroadcastData(const std::string &data, bool skippable=false)
Sends the provided data to all the connected clients.
bool BroadcastBinaryData(const std::string &data, bool skippable=false)
Sends the provided binary data to all the connected clients.
void RegisterMessageHandler(std::string type, MessageHandler handler)
Add a new message handler for a message type.
bool SendData(Connection *conn, const std::string &data, bool skippable=false, int op_code=MG_WEBSOCKET_OPCODE_TEXT)
Sends the provided data to a specific connected client.
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
nlohmann::json Json
bool SetProtoToASCIIFile(const google::protobuf::Message &message, int file_descriptor)
Definition file.cc:43
class register implement
Definition arena_queue.h:37
optional VehicleParam vehicle_param