HomeScreenBinding
libhomescreen.cpp
Go to the documentation of this file.
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 <stdarg.h>
18 #include <sys/socket.h>
19 #include <iostream>
20 #include <algorithm>
21 #include <thread>
22 #include <errno.h>
23 #include <cassert>
24 #include <cctype>
25 #include <cerrno>
26 #include <cstdio>
27 #include <cstdlib>
28 #include <cstring>
29 
30 #include <libhomescreen.hpp>
31 #include "hmi-debug.h"
32 
33 using namespace std;
34 
35 static bool has_verb(const string& verb);
36 static const char API[] = "homescreen";
37 
38 const std::vector<std::string> LibHomeScreen::api_list {
39  std::string("ping"), // debug do not use
40  std::string("tap_shortcut"), // HomeScreen Application only
41  std::string("on_screen_message"),
42  std::string("on_screen_reply"),
43  std::string("subscribe"),
44  std::string("unsubscribe")
45 };
46 
47 const std::vector<std::string> LibHomeScreen::event_list {
48  std::string("tap_shortcut"),
49  std::string("on_screen_message"),
50  std::string("on_screen_reply"),
51  std::string("none")
52 };
53 
54 
59 static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
60 {
61  static_cast<LibHomeScreen*>(closure)->on_hangup(NULL,wsj);
62 }
63 
64 static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
65 {
66  /* LibHomeScreen is not called from other process */
67 }
68 
69 static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
70 {
71  static_cast<LibHomeScreen*>(closure)->on_event(NULL,event,msg);
72 }
73 
74 static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
75 {
76  static_cast<LibHomeScreen*>(closure)->on_reply(NULL,msg);
77 }
78 
79 
84 {
85 }
86 
91 {
92  if(mploop)
93  {
94  sd_event_unref(mploop);
95  }
96  if(sp_websock != NULL)
97  {
98  afb_wsj1_unref(sp_websock);
99  }
100 }
101 
116 int LibHomeScreen::init(const int port, const string& token)
117 {
118  int ret = 0;
119  if(port > 0 && token.size() > 0)
120  {
121  mport = port;
122  mtoken = token;
123  }
124  else
125  {
126  HMI_ERROR("libhomescreen","port and token should be > 0, Initial port and token uses.");
127  }
128 
129  ret = initialize_websocket();
130  if(ret != 0 )
131  {
132  HMI_ERROR("libhomescreen","Failed to initialize websocket");
133  }
134  else{
135  HMI_DEBUG("libhomescreen","Initialized");
136  }
137 
138  return ret;
139 }
140 
156  void (*event_cb)(const std::string& event, struct json_object* event_contents),
157  void (*reply_cb)(struct json_object* reply_contents),
158  void (*hangup_cb)(void))
159 {
160  onEvent = event_cb;
161  onReply = reply_cb;
162  onHangup = hangup_cb;
163 }
164 
165 int LibHomeScreen::initialize_websocket()
166 {
167  mploop = NULL;
168  onEvent = nullptr;
169  onReply = nullptr;
170  int ret = sd_event_default(&mploop);
171  if(ret < 0)
172  {
173  HMI_ERROR("libhomescreen","Failed to create event loop");
174  goto END;
175  }
176 
177  /* Initialize interface from websocket */
178  minterface.on_hangup = _on_hangup_static;
179  minterface.on_call = _on_call_static; /* Is this necessary? */
180  minterface.on_event = _on_event_static;
181  muri += "ws://localhost:" + to_string(mport) + "/api?token=" + mtoken; /*To be modified*/
182  sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
183  if(sp_websock == NULL)
184  {
185  HMI_ERROR("libhomescreen","Failed to create websocket connection");
186  goto END;
187  }
188 
189  /* creates the evsrc */
190  //ret = sd_event_add_io(mploop,&mevent_src, sp_websock->fd, EPOLLIN, event_callback, NULL);
191 
192  return 0;
193 END:
194  if(mploop)
195  {
196  sd_event_unref(mploop);
197  }
198  return -1;
199 }
200 
201 static void *event_loop_run(void *args)
202 {
203  struct sd_event* loop = (struct sd_event*)(args);
204  HMI_DEBUG("libhomescreen","start eventloop");
205  for(;;)
206  sd_event_run(loop, 30000000);
207 }
208 
220 int LibHomeScreen::tapShortcut(const char* application_name)
221 {
222  if(!sp_websock)
223  {
224  return -1;
225  }
226 
227  struct json_object* j_obj = json_object_new_object();
228  struct json_object* val = json_object_new_string(application_name);
229  json_object_object_add(j_obj, "application_name", val);
230  return this->call("tap_shortcut", j_obj);
231 }
232 
244 int LibHomeScreen::onScreenMessage(const char* display_message)
245 {
246  if(!sp_websock)
247  {
248  return -1;
249  }
250 
251  struct json_object* j_obj = json_object_new_object();
252  struct json_object* val = json_object_new_string(display_message);
253  json_object_object_add(j_obj, "display_message", val);
254  return this->call("on_screen_message", j_obj);
255 }
256 
268 int LibHomeScreen::onScreenReply(const char* reply_message)
269 {
270  if(!sp_websock)
271  {
272  return -1;
273  }
274 
275  struct json_object* j_obj = json_object_new_object();
276  struct json_object* val = json_object_new_string(reply_message);
277  json_object_object_add(j_obj, "reply_message", val);
278  return this->call("on_screen_reply", j_obj);
279 }
280 
294 {
295  if (et >= 1 && et <= 3) {
296  switch (et) {
297  case Event_TapShortcut:
299  break;
300  case Event_OnScreenMessage:
302  break;
303  case Event_OnScreenReply:
305  break;
306  }
307 
308  this->handlers[et] = std::move(f);
309  }
310 }
311 
326 int LibHomeScreen::call(const string& verb, struct json_object* arg)
327 {
328  int ret;
329  if(!sp_websock)
330  {
331  return -1;
332  }
333  if (!has_verb(verb))
334  {
335  HMI_ERROR("libhomescreen","verb doesn't exit");
336  return -1;
337  }
338  ret = afb_wsj1_call_j(sp_websock, API, verb.c_str(), arg, _on_reply_static, this);
339  if (ret < 0) {
340  HMI_ERROR("libhomescreen","Failed to call verb:%s",verb.c_str());
341  }
342  return ret;
343 }
344 
360 int LibHomeScreen::call(const char* verb, struct json_object* arg)
361 {
362  int ret;
363  if(!sp_websock)
364  {
365  return -1;
366  }
367  if (!has_verb(string(verb)))
368  {
369  HMI_ERROR("libhomescreen","verb doesn't exit");
370  return -1;
371  }
372  ret = afb_wsj1_call_j(sp_websock, API, verb, arg, _on_reply_static, this);
373  if (ret < 0) {
374  HMI_ERROR("libhomescreen","Failed to call verb:%s",verb);
375  }
376  return ret;
377 }
378 
392 int LibHomeScreen::subscribe(const string& event_name)
393 {
394  if(!sp_websock)
395  {
396  return -1;
397  }
398  struct json_object* j_obj = json_object_new_object();
399  json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
400 
401  int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _on_reply_static, this);
402  if (ret < 0) {
403  HMI_ERROR("libhomescreen","Failed to call verb:%s",__FUNCTION__);
404  }
405  return ret;
406 }
407 
421 int LibHomeScreen::unsubscribe(const string& event_name)
422 {
423  if(!sp_websock)
424  {
425  return -1;
426  }
427  struct json_object* j_obj = json_object_new_object();
428  json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
429 
430  int ret = afb_wsj1_call_j(sp_websock, API, "unsubscribe", j_obj, _on_reply_static, this);
431  if (ret < 0) {
432  HMI_ERROR("libhomescreen","Failed to call verb:%s",__FUNCTION__);
433  }
434  return ret;
435 }
436 
437 /************* Callback Function *************/
438 
439 void LibHomeScreen::on_hangup(void *closure, struct afb_wsj1 *wsj)
440 {
441  HMI_DEBUG("libhomescreen","%s called", __FUNCTION__);
442  if(onHangup != nullptr)
443  {
444  onHangup();
445  }
446 }
447 
448 void LibHomeScreen::on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
449 {
450 }
451 
452 /*
453 * event is like "homescreen/tap_shortcut"
454 * msg is like {"event":"homescreen\/tap_shortcut","data":{"application_name":"hoge"},"jtype":"afb-event"}
455 * so you can get
456  event name : struct json_object obj = json_object_object_get(msg,"event")
457 */
458 void LibHomeScreen::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
459 {
460  HMI_DEBUG("libhomescreen","event: (%s) msg: (%s).", event, afb_wsj1_msg_object_s(msg));
461 
462  if (strstr(event, API) == NULL) {
463  return;
464  }
465 
466  struct json_object* ev_contents = afb_wsj1_msg_object_j(msg);
467  struct json_object *json_data = json_object_object_get(ev_contents, "data");
468 
469  if(onEvent != nullptr)
470  {
471  const string ev(event);
472  onEvent(ev, ev_contents);
473  }
474 
475  const char* event_only = strchr(event, '/');
476  if (event_only != nullptr) {
477  event_only = event_only + 1;
478  }
479 
480  if (strcasecmp(event_only, LibHomeScreen::event_list[0].c_str()) == 0) {
481  auto i = this->handlers.find(Event_TapShortcut);
482  if ( i != this->handlers.end() ) {
483  i->second(json_data);
484  }
485  }
486  else if (strcasecmp(event_only, LibHomeScreen::event_list[1].c_str()) == 0) {
487  auto i = this->handlers.find(Event_OnScreenMessage);
488  if ( i != this->handlers.end() ) {
489  i->second(json_data);
490  }
491  }
492  else if (strcasecmp(event_only, LibHomeScreen::event_list[2].c_str()) == 0) {
493  auto i = this->handlers.find(Event_OnScreenReply);
494  if ( i != this->handlers.end() ) {
495  i->second(json_data);
496  }
497  }
498 
499  json_object_put(ev_contents);
500 }
501 
506 void LibHomeScreen::on_reply(void *closure, struct afb_wsj1_msg *msg)
507 {
508  HMI_DEBUG("libhomescreen","msg: (%s)", afb_wsj1_msg_object_s(msg));
509  if(onReply != nullptr)
510  {
511  struct json_object* reply = afb_wsj1_msg_object_j(msg);
512  onReply(reply);
513 
514  json_object_put(reply);
515  }
516 }
517 
518 static bool has_verb(const string& verb)
519 {
520  HMI_DEBUG("libhomescreen","verb is %s", verb.c_str());
521  if(find(LibHomeScreen::api_list.begin(), LibHomeScreen::api_list.end(), verb) != LibHomeScreen::api_list.end())
522  return true;
523  else
524  return false;
525 }
void on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
#define HMI_ERROR(prefix, args,...)
Definition: hmi-debug.h:18
static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
void on_reply(void *closure, struct afb_wsj1_msg *msg)
int onScreenReply(const char *reply_message)
std::function< void(json_object *)> handler_func
#define HMI_DEBUG(prefix, args,...)
Definition: hmi-debug.h:22
void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
static const char API[]
int call(const std::string &verb, struct json_object *arg)
static void * event_loop_run(void *args)
void on_hangup(void *closure, struct afb_wsj1 *wsj)
int tapShortcut(const char *application_name)
int subscribe(const std::string &event_name)
static const std::vector< std::string > event_list
static void subscribe(struct afb_req request)
Definition: homescreen.c:189
int init(const int port, const std::string &token)
static bool has_verb(const string &verb)
static void _on_event_static(void *closure, const char *event, struct afb_wsj1_msg *msg)
int onScreenMessage(const char *display_message)
static const std::vector< std::string > api_list
int unsubscribe(const std::string &event_name)
void set_event_handler(enum EventType et, handler_func f)
void registerCallback(void(*event_cb)(const std::string &event, struct json_object *event_contents), void(*reply_cb)(struct json_object *reply_contents), void(*hangup_cb)(void)=nullptr)
static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)