From 3e94024998c1615bd30306aab7537db22161a9ce Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 19 Oct 2019 13:45:11 -0700 Subject: binding: navigation: rewrite of navigation binding To remove dependency on DBus the binding needed to be rewritten to output pure JSON output to subscribed consumers. Bug-AGL: SPEC-2880 Change-Id: Ie85dfccd42ca36119116a0fbfb16bf4e96efc184 Signed-off-by: Matt Ranostay --- binding/CMakeLists.txt | 35 +++++++ binding/navigation-api.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++ binding/navigation-api.h | 53 ++++++++++ 3 files changed, 333 insertions(+) create mode 100644 binding/CMakeLists.txt create mode 100644 binding/navigation-api.c create mode 100644 binding/navigation-api.h (limited to 'binding') diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt new file mode 100644 index 0000000..9088825 --- /dev/null +++ b/binding/CMakeLists.txt @@ -0,0 +1,35 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll +# contrib: Romain Forlot +# +# 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. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(afm-navigation-binding) + + # Define project Targets + add_library(afm-navigation-binding MODULE navigation-api.c) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "lib" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} ${link_libraries}) diff --git a/binding/navigation-api.c b/binding/navigation-api.c new file mode 100644 index 0000000..d9ea285 --- /dev/null +++ b/binding/navigation-api.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2019 Konsulko Group + * Author: Matt Ranostay + * + * 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 + +#define AFB_BINDING_VERSION 3 +#include + +#include "navigation-api.h" + +struct navigation_state *navigation_get_userdata(afb_req_t request) { + afb_api_t api = afb_req_get_api(request); + return afb_api_get_userdata(api); +} + +static afb_event_t get_event_from_value(struct navigation_state *ns, + const char *value) +{ + if (!g_strcmp0(value, "status")) + return ns->status_event; + + if (!g_strcmp0(value, "position")) + return ns->position_event; + + if (!g_strcmp0(value, "waypoints")) + return ns->waypoints_event; + + return NULL; +} + +static json_object **get_storage_from_value(struct navigation_state *ns, + const char *value) +{ + if (!g_strcmp0(value, "status")) + return &ns->status_storage; + + if (!g_strcmp0(value, "position")) + return &ns->position_storage; + + if (!g_strcmp0(value, "waypoints")) + return &ns->waypoints_storage; + + return NULL; +} + +static void navigation_subscribe_unsubscribe(afb_req_t request, + gboolean unsub) +{ + struct navigation_state *ns = navigation_get_userdata(request); + json_object *jresp = json_object_new_object(); + const char *value; + afb_event_t event; + int rc; + + value = afb_req_value(request, "value"); + if (!value) { + afb_req_fail_f(request, "failed", "Missing \"value\" event"); + return; + } + + event = get_event_from_value(ns, value); + if (!event) { + afb_req_fail_f(request, "failed", "Bad \"value\" event \"%s\"", + value); + return; + } + + if (!unsub) { + json_object *storage; + rc = afb_req_subscribe(request, event); + + g_rw_lock_reader_lock(&ns->rw_lock); + storage = *get_storage_from_value(ns, value); + if (storage) { + // increment reference counter, and send out cached value + json_object_get(storage); + afb_event_push(event, storage); + } + g_rw_lock_reader_unlock(&ns->rw_lock); + } else { + rc = afb_req_unsubscribe(request, event); + } + if (rc != 0) { + afb_req_fail_f(request, "failed", + "%s error on \"value\" event \"%s\"", + !unsub ? "subscribe" : "unsubscribe", + value); + return; + } + + afb_req_success_f(request, jresp, "Navigation %s to event \"%s\"", + !unsub ? "subscribed" : "unsubscribed", + value); +} + +static void subscribe(afb_req_t request) +{ + navigation_subscribe_unsubscribe(request, FALSE); +} + +static void unsubscribe(afb_req_t request) +{ + navigation_subscribe_unsubscribe(request, TRUE); +} + +static void broadcast(afb_req_t request, const char *name, gboolean cache) +{ + struct navigation_state *ns = navigation_get_userdata(request); + afb_event_t event = get_event_from_value(ns, name); + json_object *jresp = afb_req_json(request); + + if (cache) { + json_object **storage = get_storage_from_value(ns, name); + + g_rw_lock_writer_lock(&ns->rw_lock); + + if (*storage) + json_object_put(*storage); + + // increment reference for storage + json_object_get(jresp); + *storage = jresp; + + g_rw_lock_writer_unlock(&ns->rw_lock); + } + + // increment reference for event + json_object_get(jresp); + afb_event_push(event, jresp); +} + +static void broadcast_status(afb_req_t request) +{ + broadcast(request, "status", TRUE); + + afb_req_success(request, NULL, "Broadcast status send"); +} + +static void broadcast_position(afb_req_t request) +{ + const char *position = afb_req_value(request, "position"); + gboolean cache = FALSE; + + // only send out a car position event on subscribe + if (position && !g_strcmp0(position, "car")) + cache = TRUE; + + broadcast(request, "position", cache); + + afb_req_success(request, NULL, "Broadcast position send"); +} + +static void broadcast_waypoints(afb_req_t request) +{ + broadcast(request, "waypoints", TRUE); + + afb_req_success(request, NULL, "Broadcast waypoints send"); +} + +static int init(afb_api_t api) +{ + struct navigation_state *ns; + + ns = g_try_malloc0(sizeof(*ns)); + if (!ns) { + AFB_ERROR("out of memory allocating navigation state"); + return -ENOMEM; + } + + ns->status_event = afb_daemon_make_event("status"); + ns->position_event = afb_daemon_make_event("position"); + ns->waypoints_event = afb_daemon_make_event("waypoints"); + + if (!afb_event_is_valid(ns->status_event) || + !afb_event_is_valid(ns->position_event) || + !afb_event_is_valid(ns->waypoints_event)) { + AFB_ERROR("Cannot create events"); + return -EINVAL; + } + + afb_api_set_userdata(api, ns); + + g_rw_lock_init(&ns->rw_lock); + + return 0; +} + +static const afb_verb_t binding_verbs[] = { + { + .verb = "subscribe", + .callback = subscribe, + .info = "Subscribe to event" + }, { + .verb = "unsubscribe", + .callback = unsubscribe, + .info = "Unsubscribe to event" + }, { + .verb = "broadcast_status", + .callback = broadcast_status, + .info = "Allows clients to broadcast status events" + }, { + .verb = "broadcast_position", + .callback = broadcast_position, + .info = "Broadcast out position event" + }, { + .verb = "broadcast_waypoints", + .callback = broadcast_waypoints, + .info = "Broadcast out waypoint event" + }, + {} +}; + +/* + * description of the binding for afb-daemon + */ +const afb_binding_t afbBindingV3 = { + .api = "navigation", + .verbs = binding_verbs, + .init = init, +}; diff --git a/binding/navigation-api.h b/binding/navigation-api.h new file mode 100644 index 0000000..457a87d --- /dev/null +++ b/binding/navigation-api.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 Konsulko Group + * Author: Matt Ranostay + * + * 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. + */ + +#ifndef NAVIGATION_API_H +#define NAVIGATION_API_H + +#include + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 3 +#include + +#include + +struct call_work; + +struct navigation_state { + // events + afb_event_t status_event; + afb_event_t position_event; + afb_event_t waypoints_event; + + // storage + json_object *status_storage; + json_object *position_storage; + json_object *waypoints_storage; + + // locking + GRWLock rw_lock; +}; + +#endif -- cgit 1.2.3-korg