Add boot sequence and multi ecu transfer
[apps/agl-service-windowmanager.git] / src / wm_connection.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
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
17 #include "wm_connection.hpp"
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include "json_helper.hpp"
25 #include "util.hpp"
26
27 extern "C"
28 {
29 #include <afb/afb-binding.h>
30 #include <systemd/sd-event.h>
31 }
32
33
34 /**
35  * namespace wm
36  */
37 namespace wm
38 {
39
40
41 namespace
42 {
43
44 static const char kPathConnectionConfigFile[] = "/etc/hmi-config/connection.json";
45 static const char kPathTimeoutConfigFile[] = "/etc/timeout.json";
46 static const char kDefaultIpAddr[] = "192.168.10.10";
47 static const int  kDefaultPort     = 4000;
48 static const uint64_t  kDefaultTimes    = 60000;
49 static const uint64_t  kDefaultSleep    = 50;
50 static struct sd_event_source *g_limit_timer_src = nullptr;
51 static struct sd_event_source *g_sleep_timer_src = nullptr;
52
53 static int setTimer(sd_event_source **src, uint64_t usec, void* handler, void* data)
54 {
55     int ret = sd_event_add_time(afb_daemon_get_event_loop(), src,
56             CLOCK_BOOTTIME, usec, 1, (sd_event_time_handler_t)handler, data);
57
58     if (ret < 0)
59     {
60         HMI_ERROR("Colud't set timer");
61     }
62
63     return ret;
64 }
65
66 static void updateTimer(sd_event_source *src, uint64_t usec)
67 {
68    sd_event_source_set_time(src, usec);
69    sd_event_source_set_enabled(src, SD_EVENT_ONESHOT);
70 }
71
72 static void stopEvent(sd_event_source *src)
73 {
74     int ret = sd_event_source_set_enabled(src, SD_EVENT_OFF);
75     if (ret < 0)
76     {
77         HMI_ERROR("Not set SD_EVENT_OFF (%s)", strerror(-ret));
78     }
79     sd_event_source_unref(src);
80 }
81
82 static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data)
83 {
84     WMConnection *p_wmcon = (WMConnection*)data;
85
86     json_object *j_out[10];
87         int j_cnt;
88     int ret = p_wmcon->receive(j_out, &j_cnt, fd);
89     if (0 > ret)
90     {
91         return 0;
92     }
93
94         for(int i = 0; i < j_cnt; i++)
95         {
96                 const char* rq = jh::getStringFromJson(j_out[i], "req");
97                 const char* id = jh::getStringFromJson(j_out[i], "appid");
98                 const char* dn = jh::getStringFromJson(j_out[i], "drawing_name");
99                 const char* da = jh::getStringFromJson(j_out[i], "drawing_area");
100                 
101                 HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da);
102
103                 // Callback
104                 p_wmcon->callOnReceivedHandler(j_out[i]);
105         }
106
107     return 0;
108 }
109
110 static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data)
111 {
112     WMConnection *p_wmcon = (WMConnection*)data;
113
114     p_wmcon->serverAccept(fd);
115
116     return 0;
117 }
118
119 static int onIoEventConnected(sd_event_source *src, int fd, uint32_t revents, void * data)
120 {
121     WMConnection *p_wmcon = (WMConnection*)data;
122
123     int ret = p_wmcon->connectedToServer(fd);
124
125     if (ret == 0)
126     {
127         stopEvent(src);
128
129         ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
130                           fd, EPOLLIN, onIoEventReceive, p_wmcon);
131     }
132
133     return ret;
134 }
135
136 static int sleepTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
137 {
138     WMConnection *p_wmcon = (WMConnection*)userdata;
139
140     int ret = p_wmcon->connectToEcu();
141
142     return ret;
143 }
144
145 static void limitTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
146 {
147     WMConnection *p_wmcon = (WMConnection*)userdata;
148
149     p_wmcon->connectionTimeLimit();
150 }
151
152 } // namespace
153
154 WMConnection::WMConnection()
155 {
156     this->end_init = false;
157
158     //Load timeout config file
159     this->loadTimeoutConfigFile();
160
161     // Load connection config file
162     this->loadConnectionConfigFile();
163
164     // TODO: ECU name should be decide by config file
165     this->ecu_name = this->mode;
166 }
167
168 int WMConnection::initialize()
169 {
170     int ret;
171     uint64_t sleepTime, limitTime;
172
173     // Initialize for Master/Slave
174     ret = this->initializeServer();
175
176     sleepTime = getNextTimerTime(this->sleep);
177
178     if (sleepTime <= 0)
179     {
180         HMI_ERROR("Cloud't get Next Timer");
181         goto connection_init_error;
182     }
183
184     ret = setTimer(&g_sleep_timer_src, sleepTime, (void *)sleepTimerHandler, this);
185     sd_event_source_set_enabled(g_sleep_timer_src, SD_EVENT_OFF);
186
187     limitTime = getNextTimerTime(this->times);
188
189     if (limitTime <= 0)
190     {
191         HMI_ERROR("Cloud't get Next Timer");
192         goto connection_init_error;
193     }
194
195     ret = setTimer(&g_limit_timer_src, limitTime, (void *)limitTimerHandler, this);
196
197     this->connectToEcu();
198
199     return ret;
200
201
202 connection_init_error:
203     HMI_ERROR("Connection Initialize Failed");
204     return -1;
205 }
206
207 void WMConnection::registerCallback(ReceivedHandler on_received)
208 {
209     this->onReceived = on_received;
210 }
211
212 int WMConnection::sendRequest(char const *req, char const *appid,
213                               char const *drawing_name, char const *drawing_area)
214 {
215     int ret;
216     json_object *j_obj = json_object_new_object();
217     json_object_object_add(j_obj, "req",          json_object_new_string(req));
218     json_object_object_add(j_obj, "appid",        json_object_new_string(appid));
219     json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name));
220     json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area));
221
222     std::string ecu_name = getAppIdToEcuName(appid);
223
224     HMI_DEBUG("send ecu_name %s", ecu_name.c_str());
225
226     ret = this->send(j_obj, ecu_name);
227
228     json_object_put(j_obj);
229
230     return ret;
231 }
232
233 int WMConnection::send(struct json_object* j_in, std::string ecu_name)
234 {
235     SocketInfo *socketData = &this->wm_socket[ecu_name];
236
237     // Convert json_object to string to send
238     const char *buf = json_object_to_json_string(j_in);
239     if (nullptr == buf)
240     {
241         HMI_ERROR("Failed to convert json_object to string");
242         return -1;
243     }
244
245     int len = strlen(buf);
246
247     HMI_DEBUG("Send data(len:%d): %s", len, buf);
248
249     int n = write(socketData->connectedSocket(), buf, len);
250     if(0 > n)
251     {
252         HMI_ERROR("Failed to send data (%s)", strerror(errno));
253         return -1;
254     }
255
256     return 0;
257 }
258
259 bool WMConnection::isRemoteArea(const char* area)
260 {
261     if (nullptr == area)
262     {
263         return false;
264     }
265
266     std::string str_area = std::string(area);
267     if ("" == str_area)
268     {
269         return false;
270     }
271
272     std::vector<std::string> elements;
273     elements = parseString(str_area, '.');
274
275     for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
276     {
277         if (itr->first == elements[0])
278         {
279             if (itr->first != this->ecu_name)
280             {
281                 return true;
282             }
283             else
284             {
285                 return false;
286             }
287         }
288     }
289
290     return false;
291 }
292
293 bool WMConnection::isConnecting(std::string ecu_name)
294 {
295     return (0 > this->wm_socket[ecu_name].connectedSocket()) ? false : true;
296 }
297
298 bool WMConnection::isConnectionMode()
299 {
300     return (Mode_Connection == this->wm_mode) ? true : false;
301 }
302
303 std::string WMConnection::parseMasterArea(const char* area)
304 {
305     std::string ret_area = "";
306     std::vector<std::string> elements;
307     elements = parseString(std::string(area), '.');
308
309     if ("master" != elements[0])
310     {
311         return std::string(area);
312     }
313
314     for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
315     {
316         ret_area += *itr;
317
318         if ((elements.end() - 1) != itr)
319         {
320             ret_area += ".";
321         }
322     }
323     return ret_area;
324 }
325
326 bool WMConnection::isSyncDrawingForRemote(const char* appid)
327 {
328     if (std::string(appid) == this->syndDrawingAppId)
329     {
330         return true;
331     }
332     else
333     {
334         return false;
335     }
336 }
337
338 void WMConnection::startSyncDrawForRemote(const char* appid)
339 {
340     this->syndDrawingAppId = std::string(appid);
341 }
342
343 void WMConnection::finishSyncDrawForRemote(const char* appid)
344 {
345     if (std::string(appid) == this->syndDrawingAppId)
346     {
347         this->syndDrawingAppId = "";
348     }
349 }
350
351 std::string WMConnection::getAreaToEcuName(const char* area)
352 {
353     std::string result;
354     std::string str_area = std::string(area);
355
356     if (str_area.find('.') != std::string::npos)
357     {
358         std::vector<std::string> elements;
359         elements = parseString(str_area, '.');
360         result = elements[0];
361     }
362     else
363     {
364         result = str_area;
365     }
366
367     return result;
368 }
369
370 std::string WMConnection::getSocketToEcuName(int socket)
371 {
372     for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
373     {
374         if (socket == itr->second.connectedSocket())
375         {
376             return itr->first;
377         }
378     }
379
380     return "";
381 }
382
383 std::string WMConnection::getMySocketToEcuName(int socket)
384 {
385     for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
386     {
387         if (socket == itr->second.mySocket())
388         {
389             return itr->first;
390         }
391     }
392
393     return "";
394 }
395
396 std::string WMConnection::getAppIdToEcuName(std::string appid)
397 {
398     if (appid2ecuName.count(appid) == 1)
399     {
400         return this->appid2ecuName[appid];
401     }
402     else
403     {
404         return "";
405     }
406 }
407
408 std::string WMConnection::getIpToEcuName(std::string ip)
409 {
410     for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
411     {
412         if (ip == itr->second.ip())
413         {
414             return itr->first;
415         }
416     }
417
418     return "";
419 }
420
421 void WMConnection::setAppIdToEcuName(std::string appid, std::string ecu_name)
422 {
423     this->appid2ecuName[appid] = ecu_name;
424 }
425
426 void WMConnection::setAppIdToReceivedEcuName(std::string appid)
427 {
428     this->appid2ecuName[appid] = received_ecu_name;
429 }
430
431 std::string WMConnection::getEcuName()
432 {
433     return this->ecu_name;
434 }
435
436 bool WMConnection::getEndInit()
437 {
438     return this->end_init;
439 }
440
441 void WMConnection::callOnReceivedHandler(json_object *j_out)
442 {
443     this->onReceived(j_out);
444 }
445
446 int WMConnection::initializeServer()
447 {
448     int ret = 0;
449     struct sockaddr_in addr;
450
451     SocketInfo *socketData = &this->wm_socket[this->ecu_name];
452
453     // Create socket
454     socketData->setMySocket(socket(AF_INET, SOCK_STREAM, 0));
455     if (0 > socketData->mySocket())
456     {
457         HMI_ERROR("Failed to create socket (%s)", strerror(errno));
458         return -1;
459     }
460
461     socketData->setConnectedSocket(socketData->mySocket());
462
463     // Bind socket
464     addr.sin_family = AF_INET;
465     addr.sin_port = htons(socketData->wmPort());
466     addr.sin_addr.s_addr = htonl(INADDR_ANY);
467
468     ret = bind(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
469     if (0 > ret)
470     {
471         HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
472         return -1;
473     }
474
475     // Listen connection
476     ret = listen(socketData->mySocket(), 1);
477     if (0 > ret)
478     {
479         HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
480         return -1;
481     }
482
483     // Register callback to accept connection
484     ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
485                           socketData->mySocket(), EPOLLIN,
486                           onIoEventAccept, this);
487     if (0 > ret)
488     {
489         HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
490         return -1;
491     }
492
493     return ret;
494 }
495
496 int WMConnection::initializeClient(std::string ecu_name)
497 {
498     SocketInfo *socketData = &this->wm_socket[ecu_name];
499
500     if (socketData->mySocket() != -1)
501     {
502         close(socketData->mySocket());
503     }
504
505     // Create socket
506     int my_socket = socket(AF_INET, SOCK_STREAM, 0);
507     if (0 > my_socket)
508     {
509         HMI_ERROR("Failed to create socket (%s)", strerror(errno));
510         return -1;
511     }
512
513     socketData->setMySocket(my_socket);
514
515     return 0;
516 }
517
518 int WMConnection::connectToEcu()
519 {
520     int cnt = 0;
521
522     HMI_DEBUG("Start Connection");
523
524     if (this->wm_socket.empty())
525     {
526         HMI_DEBUG("Connection destination is not written to connection.json");
527         stopEvent(g_limit_timer_src);
528         stopEvent(g_sleep_timer_src);
529
530         this->end_init = true;
531         this->wm_mode = Mode_Standalone;
532
533         return 0;
534     }
535
536     for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
537     {
538         std::string ecu_name = itr->first;
539         HMI_DEBUG("ECU Names %s", ecu_name.c_str());
540
541         if (itr->second.connectedSocket() != -1 || !itr->second.masterMode())
542         {
543             cnt++;
544             HMI_DEBUG("Already Connected");
545             continue;
546         }
547
548         if (itr->second.masterMode())
549         {
550             HMI_DEBUG("Try Connection");
551             connectToServer(ecu_name);
552         }
553     }
554
555     if (cnt == (int)this->wm_socket.size())
556     {
557         HMI_DEBUG("All Connected!!");
558
559         stopEvent(g_sleep_timer_src);
560         stopEvent(g_limit_timer_src);
561
562         this->end_init = true;
563         this->wm_mode = Mode_Connection;
564
565         return 0;
566     }
567
568     uint64_t sleepTime = getNextTimerTime(this->sleep);
569     updateTimer(g_sleep_timer_src, sleepTime);
570
571     return 0;
572 }
573
574 void WMConnection::connectionTimeLimit()
575 {
576     HMI_DEBUG("Time Limit");
577
578     stopEvent(g_sleep_timer_src);
579     stopEvent(g_limit_timer_src);
580
581     this->wm_socket[this->ecu_name].setConnectedSocket(-1);
582     this->wm_mode = Mode_Standalone;
583
584     for (auto itr = this->wm_socket.begin(); itr != this->wm_socket.end(); ++itr)
585     {
586         if (itr->second.connectedSocket() != -1)
587         {
588             HMI_DEBUG("Connection Mode");
589             this->wm_mode = Mode_Connection;
590         }
591         else
592         {
593             close(itr->second.mySocket());
594         }
595     }
596
597     if (this->wm_mode == Mode_Standalone)
598     {
599         close(this->wm_socket[this->ecu_name].mySocket());
600     }
601
602     this->end_init = true;
603 }
604
605 int WMConnection::connectToServer(std::string ecu_name)
606 {
607     int ret = 0;
608     struct sockaddr_in addr;
609
610     this->initializeClient(ecu_name);
611
612     SocketInfo *socketData = &wm_socket[ecu_name];
613
614     // Connect to master
615     addr.sin_family = AF_INET;
616     addr.sin_port = htons(socketData->wmPort());
617     addr.sin_addr.s_addr = inet_addr(socketData->ip().c_str());
618
619     connect(socketData->mySocket(), (struct sockaddr *)&addr, sizeof(addr));
620
621     ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
622                         socketData->mySocket(), EPOLLOUT,
623                         onIoEventConnected, this);
624
625     if (0 > ret)
626     {
627         HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
628         return -1;
629     }
630
631     return ret;
632 }
633
634 int WMConnection::connectedToServer(int socket)
635 {
636     int ret;
637
638     struct sockaddr_in addr;
639     socklen_t addr_len = sizeof(addr);
640
641     std::string ecu_name = getMySocketToEcuName(socket);
642
643     ret = getpeername(socket, (struct sockaddr*)&addr, &addr_len);
644
645     if (ret != 0)
646     {
647         HMI_DEBUG("Failed to connect %s (%s)", ecu_name.c_str(), strerror(errno));
648         return -1;
649     }
650
651     HMI_DEBUG("Connected to %s", ecu_name.c_str());
652
653     SocketInfo *socketData = &this->wm_socket[ecu_name];
654
655     // Store connected socket
656     socketData->setConnectedSocket(socket);
657
658     return 0;
659 }
660
661 int WMConnection::serverAccept(int socket)
662 {
663     struct sockaddr_in addr;
664
665     // Accept connection
666     socklen_t len = sizeof(addr);
667     int my_socket = this->wm_socket[this->getEcuName()].mySocket();
668     int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
669     if (0 > connected_socket)
670     {
671         HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
672         return -1;
673     }
674
675     std::string ip = inet_ntoa(addr.sin_addr);
676     std::string ecu_name = getIpToEcuName(ip);
677
678     SocketInfo *socketData = &this->wm_socket[ecu_name];
679
680     // Store connected socket
681     socketData->setConnectedSocket(connected_socket);
682
683     // Register callback to receive
684     int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
685                           connected_socket, EPOLLIN,
686                           onIoEventReceive, this);
687     if (0 > ret)
688     {
689         HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
690         return -1;
691     }
692
693     return 0;
694 }
695
696 int WMConnection::receive(json_object** j_out, int *j_cnt, int socket)
697 {
698     char buf[1024] = {};
699     int n;
700
701     n = read(socket, buf, sizeof(buf));
702     if(0 > n)
703     {
704         HMI_ERROR("Failed to receive data (%s)", strerror(errno));
705         return -1;
706     }
707
708     HMI_DEBUG("Received data length: %d", n);
709     HMI_DEBUG("Received data: %s", buf);
710
711         // Parse received data
712         struct json_tokener *tokener = json_tokener_new();
713         int cnt = 0;
714
715         while (n >= tokener->char_offset)
716         {
717         j_out[cnt] = json_tokener_parse_ex(tokener, &buf[tokener->char_offset], n);
718                 
719                 if (nullptr == j_out[cnt]) 
720                 {
721                         break;
722                 }
723
724                 cnt++;
725         }
726
727         *j_cnt = cnt;
728         json_tokener_free(tokener);
729
730     this->received_ecu_name = this->getSocketToEcuName(socket);
731     HMI_DEBUG("received ecu name %s", this->received_ecu_name.c_str());
732
733     return 0;
734 }
735
736 int WMConnection::loadTimeoutConfigFile()
737 {
738     // Get afm application installed dir
739     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
740     if (!afm_app_install_dir)
741     {
742         HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
743     }
744     std::string path = std::string(afm_app_install_dir) + std::string(kPathTimeoutConfigFile);
745
746     // Load connection config file
747     json_object *json_obj;
748     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
749     if (0 > ret)
750     {
751         HMI_ERROR("Could not open %s, so use default timeout", path.c_str());
752         this->times = kDefaultTimes;
753         this->sleep = kDefaultSleep;
754         return 0;
755     }
756     HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
757
758     int times = jh::getIntFromJson(json_obj, "times");
759     this->times = (0 != times) ? times : kDefaultTimes;
760
761     int sleep = jh::getIntFromJson(json_obj, "sleep");
762     this->sleep = (0 != sleep) ? sleep : kDefaultSleep;
763
764     // Release json_object
765     json_object_put(json_obj);
766
767     return 0;
768 }
769
770 int WMConnection::loadConnectionConfigFile()
771 {
772     std::string path = std::string(kPathConnectionConfigFile);
773
774     // Load connection config file
775     json_object *json_obj, *json_cfg;
776     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
777     if (0 > ret)
778     {
779         HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
780         this->wm_socket["slave"] = SocketInfo("slave", kDefaultIpAddr, kDefaultPort, false);
781         return 0;
782     }
783     HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
784
785     const char* screen_name = jh::getStringFromJson(json_obj, "screen_name");
786     this->mode = (nullptr != screen_name) ? screen_name : "slave";
787
788     int wm_port = jh::getIntFromJson(json_obj, "wm_port");
789
790     this->wm_socket[screen_name] = SocketInfo(screen_name, "", wm_port, true);
791
792     // Check
793     HMI_DEBUG("screen_name:%s wm_port:%d", screen_name, wm_port);
794
795         if (!json_object_object_get_ex(json_obj, "connections", &json_cfg))
796         {
797                 HMI_ERROR("connection.json Parse Error!!");
798                 return 0;
799         }
800
801         int len = json_object_array_length(json_cfg);
802
803         for (int i = 0; i < len; i++)
804         {
805                 json_object *json_conn = json_object_array_get_idx(json_cfg, i);
806
807                 std::string screen_name = jh::getStringFromJson(json_conn, "screen_name");
808                 std::string ip = jh::getStringFromJson(json_conn, "ip");
809                 int wm_port = jh::getIntFromJson(json_conn, "wm_port");
810         bool master_mode = jh::getBoolFromJson(json_conn, "master_mode");
811
812         this->wm_socket[screen_name] = SocketInfo(screen_name, ip, wm_port, master_mode);
813
814         HMI_DEBUG("screen_name:%s ip:%s port:%d server_mode:%s", screen_name.c_str(),
815                 ip.c_str(), wm_port, (master_mode ? "true" : "false"));
816         }
817
818     // Release json_object
819     json_object_put(json_obj);
820
821     return 0;
822 }
823
824 uint64_t WMConnection::getNextTimerTime(uint64_t msec)
825 {
826     struct timespec ts;
827
828     if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0)
829     {
830         HMI_ERROR("Could't set time (clock_gettime() returns with error");
831         return -1;
832     }
833
834     uint64_t timer_nsec = ((ts.tv_sec  * 1000000000ULL) + (ts.tv_nsec) + (msec * 1000000));
835
836     if (!timer_nsec)
837     {
838         HMI_ERROR("Second is 0");
839         return -1;
840     }
841
842     return timer_nsec / 1000;
843 }
844
845 } // namespace wm