23#include "google/protobuf/util/json_util.h"
25#include "modules/dreamview/proto/preprocess_table.pb.h"
39using google::protobuf::util::JsonStringToMessage;
45 hmi_worker_(new
HMIWorker(monitor_log_buffer_)),
46 websocket_(websocket),
47 map_service_(map_service),
48 hmi_ws_(hmi_websocket) {
50 RegisterDBMessageHandlers();
51 RegisterFrontendConfMessageHandlers();
52 RegisterMessageHandlers();
57 const std::string& channel_name,
58 nlohmann::json* subscribe_param) {
59 AINFO <<
"Start HMIStatus updater timer with data sending frequency: "
61 time_interval_ms_ = time_interval_ms;
62 if (time_interval_ms_ > 0) {
64 time_interval_ms, [
this]() { this->
OnTimer(); },
false));
71void HMI::Start(DvCallback callback_api) { hmi_worker_->Start(callback_api); }
76 AINFO <<
"HMIStatus updater timer has been stopped";
82void HMI::RegisterDBMessageHandlers() {
84 "AddOrModifyObjectToDB",
87 response[
"action"] =
"response";
88 std::string request_id;
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());
97 response[
"data"][
"requestId"] = request_id;
98 std::string key, value;
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());
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());
113 bool ret = hmi_worker_->AddOrModifyObjectToDB(key, value);
115 response[
"data"][
"info"][
"code"] = 0;
116 response[
"data"][
"info"][
"message"] =
"Success";
118 response[
"data"][
"info"][
"code"] = -1;
119 response[
"data"][
"info"][
"message"] =
120 "Failed to add or modify object to DB";
122 websocket_->
SendData(conn, response.dump());
129 response[
"action"] =
"response";
130 std::string 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());
138 response[
"data"][
"requestId"] = request_id;
139 std::string key, value;
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());
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());
158 response[
"action"] =
"response";
159 std::string 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());
167 response[
"data"][
"requestId"] = request_id;
168 std::string key, value;
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());
176 bool ret = hmi_worker_->DeleteObjectToDB(key);
178 response[
"data"][
"info"][
"code"] = 0;
179 response[
"data"][
"info"][
"message"] =
"Success";
181 response[
"data"][
"info"][
"code"] = -1;
182 response[
"data"][
"info"][
"message"] =
"Failed to delete object to DB";
184 websocket_->
SendData(conn, response.dump());
188 "GetTuplesWithTypeFromDB",
191 response[
"action"] =
"response";
192 std::string request_id;
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());
201 response[
"data"][
"requestId"] = request_id;
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());
210 auto ret = hmi_worker_->GetTuplesWithTypeFromDB(type);
211 Json tuples = Json::array();
212 for (
const auto& item : ret) {
214 tuple[
"key"] = item.first;
215 tuple[
"value"] = item.second;
216 tuples.push_back(tuple);
218 response[
"data"][
"info"][
"data"] = tuples;
219 response[
"data"][
"info"][
"code"] = 0;
220 response[
"data"][
"info"][
"message"] =
"Success";
221 websocket_->
SendData(conn, response.dump());
225void HMI::RegisterFrontendConfMessageHandlers() {
230 response[
"action"] =
"response";
231 std::string request_id;
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());
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);
244 if (current_layout.empty()) {
245 AINFO <<
"There is no current layout, returning the default.";
246 current_layout = hmi_worker_->GetCurrentModeDefaultLayout();
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());
257 response[
"action"] =
"response";
258 std::string request_id;
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());
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());
275 "GetDvPluginPanelsJson",
278 response[
"action"] =
"response";
279 std::string 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());
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());
297void HMI::RegisterMessageHandlers() {
313 response[
"action"] =
"response";
314 std::string 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());
322 response[
"data"][
"requestId"] = request_id;
326 AERROR <<
"Truncated HMIAction request.";
330 if (!HMIAction_Parse(action, &hmi_action)) {
331 AERROR <<
"Invalid HMIAction string: " << action;
337 is_ok = hmi_worker_->Trigger(hmi_action, value);
339 is_ok = hmi_worker_->Trigger(hmi_action);
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());
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());
367 uint64_t event_time_ms;
379 hmi_worker_->SubmitAudioEvent(event_time_ms, obstacle_id, audio_type,
380 moving_result, audio_direction,
382 monitor_log_buffer_.INFO(
"Audio event added.");
384 AERROR <<
"Truncated SubmitAudioEvent request.";
385 monitor_log_buffer_.WARN(
"Failed to submit an audio event.");
394 uint64_t event_time_ms;
395 std::string event_msg;
396 std::vector<std::string> event_types;
402 hmi_worker_->SubmitDriveEvent(event_time_ms, event_msg, event_types,
404 monitor_log_buffer_.INFO(
"Drive event added.");
406 AERROR <<
"Truncated SubmitDriveEvent request.";
407 monitor_log_buffer_.WARN(
"Failed to submit a drive event.");
414 std::string request_id;
416 response[
"action"] =
"response";
421 info[
"message"] =
"Miss requestId";
422 AERROR <<
"Miss required field requestId to execute play recorder "
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";
432 response[
"data"][
"info"] = info;
433 if (!request_id.empty()) {
434 response[
"data"][
"requestId"] = request_id;
436 websocket_->
SendData(conn, response.dump());
440 "ResetRecordProgress",
442 std::string request_id;
443 std::string progress_str;
445 response[
"action"] =
"response";
449 info[
"message"] =
"Miss requestId";
450 AERROR <<
"Miss required field requestId to execute play recorder "
456 info[
"message"] =
"Miss progress";
457 AERROR <<
"Miss required field progress to reset record progress.";
460 bool valid_progress =
true;
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;
471 if (valid_progress) {
472 bool result = hmi_worker_->ResetRecordProgress(progress);
473 info[
"code"] = result ? 0 : -1;
475 info[
"message"] =
"Failed to start play recorder";
479 info[
"message"] =
"Failed to get proress value";
482 response[
"data"][
"info"] = info;
483 if (!request_id.empty()) {
484 response[
"data"][
"requestId"] = request_id;
486 websocket_->
SendData(conn, response.dump());
490 "PlayRecorderAction",
492 std::string request_id;
493 std::string action_type;
496 response[
"action"] =
"response";
501 info[
"message"] =
"Error param";
502 AERROR <<
"Failed to get param to execute play recorder action.";
507 info[
"message"] =
"Miss requestId";
508 AERROR <<
"Miss required field requestId to execute play recorder "
511 }
else if (action_type.compare(
"continue") == 0 &&
514 AERROR <<
"Miss required field progress to continue play record!";
516 info[
"message"] =
"Miss progress";
518 bool exec_action_result =
519 hmi_worker_->handlePlayRecordProcess(action_type);
520 info[
"code"] = exec_action_result ? 0 : -1;
521 if (!exec_action_result) {
523 "Failed to execute play recorder action: " + action_type;
526 response[
"data"][
"info"] = info;
527 if (!request_id.empty()) {
528 response[
"data"][
"requestId"] = request_id;
530 websocket_->
SendData(conn, response.dump());
537 response[
"action"] =
"response";
538 std::string 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());
546 response[
"data"][
"requestId"] = request_id;
548 if (hmi_worker_->GetStatus().current_operation() ==
549 HMIModeOperation::Waypoint_Follow) {
550 ret = hmi_worker_->StartRtkDataRecorder();
552 ret = hmi_worker_->StartDataRecorder();
555 response[
"data"][
"info"][
"code"] = 0;
556 response[
"data"][
"info"][
"message"] =
"Success";
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";
563 websocket_->
SendData(conn, response.dump());
570 response[
"action"] =
"response";
571 std::string 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());
579 response[
"data"][
"requestId"] = request_id;
581 if (hmi_worker_->GetStatus().current_operation() ==
582 HMIModeOperation::Waypoint_Follow) {
583 ret = hmi_worker_->StopRtkDataRecorder();
585 ret = hmi_worker_->StopDataRecorder();
588 response[
"data"][
"info"][
"code"] = 0;
589 response[
"data"][
"info"][
"message"] =
"Success";
591 response[
"data"][
"info"][
"code"] = -1;
592 response[
"data"][
"info"][
"message"] =
593 "Failed to stop data recorder: failed to stop the cyber_recorder "
596 websocket_->
SendData(conn, response.dump());
600 "StartPlayRtkRecorder",
603 response[
"action"] =
"response";
604 std::string 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());
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";
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());
627 "StopPlayRtkRecorder",
630 response[
"action"] =
"response";
631 std::string 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());
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";
646 bool ret = hmi_worker_->StopPlayRtkRecorder();
648 response[
"data"][
"info"][
"code"] = 0;
649 response[
"data"][
"info"][
"message"] =
"Success";
651 response[
"data"][
"info"][
"code"] = -1;
652 response[
"data"][
"info"][
"message"] =
653 "Failed to stop play data recorder process";
655 websocket_->
SendData(conn, response.dump());
662 response[
"action"] =
"response";
663 std::string request_id, new_name;
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());
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());
678 response[
"data"][
"requestId"] = request_id;
680 if (hmi_worker_->GetStatus().current_operation() ==
681 HMIModeOperation::Waypoint_Follow) {
682 ret = hmi_worker_->SaveRtkDataRecorder(new_name);
684 ret = hmi_worker_->SaveDataRecorder(new_name);
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";
699 response[
"data"][
"info"][
"code"] = -1;
700 response[
"data"][
"info"][
"message"] =
701 "Failed to save record: please try again or check whether your "
704 websocket_->
SendData(conn, response.dump());
708 "DeleteDataRecorder",
711 response[
"action"] =
"response";
712 std::string 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());
720 response[
"data"][
"requestId"] = request_id;
722 if (hmi_worker_->GetStatus().current_operation() ==
723 HMIModeOperation::Waypoint_Follow) {
724 ret = hmi_worker_->DeleteRtkDataRecorder();
726 ret = hmi_worker_->DeleteDataRecorder();
729 response[
"data"][
"info"][
"code"] = 0;
730 response[
"data"][
"info"][
"message"] =
"Success";
732 response[
"data"][
"info"][
"code"] = -1;
733 response[
"data"][
"info"][
"message"] =
"Failed to delete the record";
735 websocket_->
SendData(conn, response.dump());
743 response[
"action"] =
"response";
744 std::string 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());
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());
767 response[
"action"] =
"response";
768 std::string 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());
776 response[
"data"][
"requestId"] = request_id;
777 bool ret = hmi_worker_->StartTerminal();
779 response[
"data"][
"info"][
"code"] = 0;
780 response[
"data"][
"info"][
"message"] =
"Success";
782 response[
"data"][
"info"][
"code"] = -1;
783 response[
"data"][
"info"][
"message"] =
"Failed to start terminal";
785 websocket_->
SendData(conn, response.dump());
790 if (websocket_ ==
nullptr) {
794 const auto& vehicle_param =
796 const std::string json_str =
798 if (conn !=
nullptr) {
799 websocket_->
SendData(conn, json_str);
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);
822 return hmi_worker_->UpdateDynamicModelToStatus(dynamic_model_name);
826 return hmi_worker_->UpdateMapToStatus(map_name);
834 hmi_worker_->UpdateCameraSensorChannelToStatus(channel_name);
839 hmi_worker_->UpdatePointCloudChannelToStatus(channel_name);
844 return hmi_worker_->isProcessRunning(process_name);
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].
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].
static bool GetStringByPath(const nlohmann::json &json, const std::string &path, std::string *value)
Get a string value from the given json and path.
static nlohmann::json ProtoToTypedJson(const std::string &json_type, const google::protobuf::Message &proto)
Convert proto to a json string.
static bool GetBoolean(const nlohmann::json &json, const std::string &key, bool *value)
Get a boolean value from the given json[key].
static bool GetNumberByPath(const nlohmann::json &json, const std::string &path, T *value)
Get a number value from the given json and path.
static bool GetString(const nlohmann::json &json, const std::string &key, std::string *value)
Get a string value from the given json[key].
Used to perform oneshot or periodic timing tasks
void StopStream(const std::string &channel_name="") override
Stop data flow.
HMI(WebSocketHandler *websocket, MapService *map_service)
void OnTimer(const std::string &channel_name="")
void StartStream(const double &time_interval_ms, const std::string &channel_name="", nlohmann::json *subscribe_param=nullptr) override
Start data flow.
bool UpdateMapToStatus(const std::string &map_name="")
bool UpdateDynamicModelToStatus(const std::string &dynamic_model_name)
bool UpdatePointChannelToStatus(const std::string &channel_name)
bool UpdateRecordToStatus()
bool UpdateCameraChannelToStatus(const std::string &channel_name)
void PublishMessage(const std::string &channel_name="") override
Publish Message to dreamview frontend.
bool isProcessRunning(const std::string &process_name)
void Start(DvCallback callback_api)
bool UpdateVehicleToStatus()
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.
bool SetProtoToASCIIFile(const google::protobuf::Message &message, int file_descriptor)
optional VehicleParam vehicle_param