/* * Copyright (c) 2017 TOYOTA MOTOR CORPORATION * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "af-steering-wheel-binding.h" #include "bind_event.h" #include "steering_wheel_json.h" #include "prop_search.h" #include "js_raw.h" #define ENABLE_EVENT_DROP struct wheel_conf { char *devname; }; int notify_property_changed(struct prop_info_t *property_info) { struct bind_event_t *event; //NOTICEMSG("notify_property_changed %s", property_info->name); event = get_event(property_info->name); if (event == NULL) { DBGMSG(": event(\"%s\") is not subscribed", property_info->name); return 1; } if (afb_event_is_valid(event->event)) { int recved_client; recved_client = afb_event_push(event->event, property2json(property_info)); if(recved_client < 1) { if(recved_client == 0) { DBGMSG("event(\"%s\") is no client.", property_info->name); #ifdef ENABLE_EVENT_DROP /* Drop event */ remove_event(property_info->name); #endif } else { ERRMSG("count of clients that received the event : %d",recved_client); } return 1; } /* else (1 <= recved_lient) * NORMAL */ } else { ERRMSG("event(\"%s\") is invalid. don't adb_event_push()", property_info->name); return 1; } return 0; } static int connection(struct wheel_conf *conf) { int js; int ret; sd_event_source *source; js = js_open(conf->devname); if (js < 0) { js_close(js); ERRMSG("can't connect to joy stick, the event loop failed"); return 0; } ret = sd_event_add_io( afb_daemon_get_event_loop(), &source, js, EPOLLIN, on_event, NULL); if (ret < 0) { js_close(js); ERRMSG("can't add event, the event loop failed"); return 0; } NOTICEMSG("connect to JS(%s), event loop started",conf->devname); return 0; } /***************************************************************************************/ /** **/ /** **/ /** SECTION: BINDING VERBS IMPLEMENTATION **/ /** **/ /** **/ /***************************************************************************************/ /** * get method. */ static void get(afb_req_t req) { } ///** // * set method. // */ //static void set(struct afb_req req) //{ // //} /** * list method. */ static struct json_object *tmplists; static void _listup_properties(struct prop_info_t *property_info) { if (property_info->name == NULL) { return; } else { json_object_array_add(tmplists, json_object_new_string(property_info->name)); } } static void list(afb_req_t req) { if (tmplists != NULL) { json_object_put(tmplists); } tmplists = json_object_new_array(); if (tmplists == NULL) { ERRMSG("not enough memory"); afb_req_reply(req, NULL, "not enough memory", NULL); return; } (void)canid_walker(_listup_properties); afb_req_reply(req, tmplists, NULL, NULL); } /** * subscribe method. */ static int subscribe_all(afb_req_t req, struct json_object *apply); static int subscribe_signal(afb_req_t req, const char *name, struct json_object *apply) { struct bind_event_t *event; if(strcmp(name, "*") == 0) { return subscribe_all(req, apply); } event = get_event(name); if (event == NULL) { event = register_event(name); if (event == NULL) { ERRMSG("register event failed: %s", name); return 1; } } else { DBGMSG("subscribe event: \"%s\" alrady exist", name); } if (afb_req_subscribe(req, event->event) != 0) { ERRMSG("afb_req_subscrive() is failed."); return 1; } json_object_object_add(apply, event->name, property2json(event->raw_info)); return 0; } static int subscribe_all(afb_req_t req, struct json_object *apply) { int i; int nProp; const char **list = getSupportPropertiesList(&nProp); int err = 0; for(i = 0; i < nProp; i++) err += subscribe_signal(req, list[i], apply); return err; } static void subscribe(afb_req_t req) { struct json_object *apply; int err = 0; const char *event; event = afb_req_value(req, "event"); if (event == NULL) { ERRMSG("Unknwon subscrive event args"); afb_req_reply(req, NULL, "error", NULL); return; } apply = json_object_new_object(); err = subscribe_signal(req, event, apply); if (!err) { afb_req_reply(req, apply, NULL, NULL); } else { json_object_put(apply); afb_req_reply(req, NULL, "error", NULL); } } /** * unsubscribe method. */ static int unsubscribe_all(afb_req_t req); static int unsubscribe_signal(afb_req_t req, const char *name) { struct bind_event_t *event; if(strcmp(name, "*") == 0) { return unsubscribe_all(req); } event = get_event(name); if (event == NULL) { ERRMSG("not subscribed event \"%s\"", name); return 0; /* Alrady unsubscribed */ } if (afb_req_unsubscribe(req, event->event) != 0) { ERRMSG("afb_req_subscrive() is failed."); return 1; } return 0; } static int unsubscribe_all(afb_req_t req) { int i; int nProp; const char **list = getSupportPropertiesList(&nProp); int err = 0; for(i = 0; i < nProp; i++) { err += unsubscribe_signal(req, list[i]); } return err; } static void unsubscribe(afb_req_t req) { struct json_object *args, *val; int n,i; int err = 0; args = afb_req_json(req); if ((args == NULL) || !json_object_object_get_ex(args, "event", &val)) { err = unsubscribe_all(req); } else if (json_object_get_type(val) != json_type_array) { err = unsubscribe_signal(req, json_object_get_string(val)); } else { struct json_object *ent; n = (int)json_object_array_length(val); for (i = 0; i < n; i++) { ent = json_object_array_get_idx(val, (size_t)i); err += unsubscribe_signal(req, json_object_get_string(ent)); } } if (!err) afb_req_reply(req, NULL, NULL, NULL); else afb_req_reply(req, NULL, "error", NULL); } /* * parse configuration file (steering_wheel.json) */ static int init_conf(int fd_conf, struct wheel_conf *conf) { #define CONF_FILE_MAX (1024) char filebuf[CONF_FILE_MAX]; json_object *jobj; memset(filebuf,0, sizeof(filebuf)); FILE *fp = fdopen(fd_conf,"r"); if (fp == NULL) { ERRMSG("canno read configuration file(steering_wheel.json)"); return -1; } fread(filebuf, 1, sizeof(filebuf), fp); fclose(fp); jobj = json_tokener_parse(filebuf); if (jobj == NULL) { ERRMSG("json: Invalid steering_wheel.json format"); return -1; } json_object_object_foreach(jobj, key, val) { if (strcmp(key,"dev_name") == 0) { conf->devname = strdup(json_object_get_string(val)); } else if (strcmp(key,"wheel_map") == 0) { wheel_define_init(json_object_get_string(val)); } else if (strcmp(key,"gear_para") == 0) { wheel_gear_para_init(json_object_get_string(val)); } } json_object_put(jobj); return 0; } static int init() { NOTICEMSG("init"); int fd_conf; struct wheel_conf conf; fd_conf = afb_daemon_rootdir_open_locale("steering_wheel.json", O_RDONLY, NULL); if (fd_conf < 0) { ERRMSG("wheel configuration (steering_wheel.json) is not access"); return -1; } if (init_conf(fd_conf, &conf)) { return -1; } return connection(&conf); } /* * array of the verbs exported to afb-daemon */ static const afb_verb_t binding_verbs[] = { /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL Authorization */ { .verb= "get", .session= AFB_SESSION_NONE, .callback= get, .info = "get", .auth = NULL }, // { .name= "set", .session= AFB_SESSION_NONE, .callback= set, .auth = NULL }, { .verb= "list", .session= AFB_SESSION_NONE, .callback= list, .info = "list", .auth = NULL }, { .verb= "subscribe", .session= AFB_SESSION_NONE, .callback= subscribe, .info = "subscribe", .auth = NULL }, { .verb= "unsubscribe", .session= AFB_SESSION_NONE, .callback= unsubscribe, .info = "unsubscribe", .auth = NULL }, { .verb= NULL } /* marker for end of the array */ }; /* * description of the binding for afb-daemon */ const afb_binding_t afbBindingExport = { .api = "steering-wheel", .specification = NULL, .verbs = binding_verbs, /* the array describing the verbs of the API */ .preinit = NULL, .init = init, .onevent = NULL, .noconcurrency = 1 };