2 * Copyright (C) 2019 Konsulko Group
3 * Author: Matt Ranostay <matt.ranostay@konsulko.com>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
27 #include <glib/gstdio.h>
29 #include <json-c/json.h>
31 #define AFB_BINDING_VERSION 3
32 #include <afb/afb-binding.h>
34 #include "navigation-api.h"
38 static const char *vshl_capabilities_events[] = {
44 struct navigation_state *navigation_get_userdata(void)
46 return afb_api_get_userdata(g_api);
49 static afb_event_t get_event_from_value(struct navigation_state *ns,
52 if (!g_strcmp0(value, "status"))
53 return ns->status_event;
55 if (!g_strcmp0(value, "position"))
56 return ns->position_event;
58 if (!g_strcmp0(value, "waypoints"))
59 return ns->waypoints_event;
64 static json_object **get_storage_from_value(struct navigation_state *ns,
67 if (!g_strcmp0(value, "status"))
68 return &ns->status_storage;
70 if (!g_strcmp0(value, "position"))
71 return &ns->position_storage;
73 if (!g_strcmp0(value, "waypoints"))
74 return &ns->waypoints_storage;
79 static void navigation_subscribe_unsubscribe(afb_req_t request,
82 struct navigation_state *ns = navigation_get_userdata();
83 json_object *jresp = NULL;
88 value = afb_req_value(request, "value");
90 afb_req_fail_f(request, "failed", "Missing \"value\" event");
94 event = get_event_from_value(ns, value);
96 afb_req_fail_f(request, "failed", "Bad \"value\" event \"%s\"",
102 json_object *storage;
103 rc = afb_req_subscribe(request, event);
105 g_rw_lock_reader_lock(&ns->rw_lock);
106 storage = *get_storage_from_value(ns, value);
108 // increment reference counter, and send out cached value
109 json_object_get(storage);
110 afb_event_push(event, storage);
112 g_rw_lock_reader_unlock(&ns->rw_lock);
114 rc = afb_req_unsubscribe(request, event);
117 afb_req_fail_f(request, "failed",
118 "%s error on \"value\" event \"%s\"",
119 !unsub ? "subscribe" : "unsubscribe",
124 jresp = json_object_new_object();
125 afb_req_success_f(request, jresp, "Navigation %s to event \"%s\"",
126 !unsub ? "subscribed" : "unsubscribed",
130 static void subscribe(afb_req_t request)
132 navigation_subscribe_unsubscribe(request, FALSE);
135 static void unsubscribe(afb_req_t request)
137 navigation_subscribe_unsubscribe(request, TRUE);
140 static void broadcast(json_object *jresp, const char *name, gboolean cache)
142 struct navigation_state *ns = navigation_get_userdata();
143 afb_event_t event = get_event_from_value(ns, name);
144 json_object *tmp = NULL;
146 if (json_object_deep_copy(jresp, (json_object **) &tmp, NULL))
150 json_object **storage;
152 g_rw_lock_writer_lock(&ns->rw_lock);
154 storage = get_storage_from_value(ns, name);
157 json_object_put(*storage);
160 // increment reference for storage
161 json_object_get(tmp);
164 // increment reference for event
165 json_object_get(tmp);
166 afb_event_push(event, tmp);
168 g_rw_lock_writer_unlock(&ns->rw_lock);
173 afb_event_push(event, tmp);
176 static void broadcast_status(afb_req_t request)
178 json_object *jresp = afb_req_json(request);
179 broadcast(jresp, "status", TRUE);
181 afb_req_success(request, NULL, "Broadcast status send");
183 // NOTE: If the Alexa SDK API for pushing local navigation
184 // updates gets exposed, send update to vshl-capabilities
188 static void broadcast_position(afb_req_t request)
190 const char *position = afb_req_value(request, "position");
191 gboolean cache = FALSE;
193 // only send out a car position event on subscribe
194 if (position && !g_strcmp0(position, "car"))
197 json_object *jresp = afb_req_json(request);
198 broadcast(jresp, "position", cache);
200 afb_req_success(request, NULL, "Broadcast position send");
202 // NOTE: If the Alexa SDK API for pushing local navigation
203 // updates gets exposed, send update to vshl-capabilities
207 static void broadcast_waypoints(afb_req_t request)
209 json_object *jresp = afb_req_json(request);
210 broadcast(jresp, "waypoints", TRUE);
212 afb_req_success(request, NULL, "Broadcast waypoints send");
214 // NOTE: If the Alexa SDK API for pushing local navigation
215 // updates gets exposed, send update to vshl-capabilities
219 static void handle_setDestination_event(struct json_object *object)
221 json_object *jdest = NULL;
222 json_object_object_get_ex(object, "destination", &jdest);
224 AFB_WARNING("setDestination event missing destination element");
228 json_object *jcoord = NULL;
229 json_object_object_get_ex(jdest, "coordinate", &jcoord);
231 AFB_WARNING("setDestination event missing coordinate element");
235 json_object *jlat = NULL;
236 json_object_object_get_ex(jcoord, "latitudeInDegrees", &jlat);
240 double lat = json_object_get_double(jlat);
244 json_object *jlon = NULL;
245 json_object_object_get_ex(jcoord, "longitudeInDegrees", &jlon);
248 double lon = json_object_get_double(jlon);
252 json_object *jobj = json_object_new_object();
253 json_object *jpoints = json_object_new_array();
254 json_object *jpoint = json_object_new_object();
255 jlat = json_object_new_double(lat);
256 jlon = json_object_new_double(lon);
257 json_object_object_add(jpoint, "latitude", jlat);
258 json_object_object_add(jpoint, "longitude", jlon);
259 json_object_array_add(jpoints, jpoint);
260 json_object_object_add(jobj, "points", jpoints);
261 broadcast(jobj, "waypoints", TRUE);
264 static void handle_cancelNavigation_event(struct json_object *object)
266 json_object *jobj = json_object_new_object();
267 json_object *jstate = json_object_new_string("stop");
268 json_object_object_add(jobj, "state", jstate);
269 broadcast(jobj, "status", TRUE);
272 static void onevent(afb_api_t api, const char *event, struct json_object *object)
277 if(strcmp(event, "vshl-capabilities/setDestination") == 0) {
278 handle_setDestination_event(object);
279 } else if(strcmp(event, "vshl-capabilities/cancelNavigation") == 0) {
280 handle_cancelNavigation_event(object);
282 AFB_WARNING("Unhandled vshl-capabilities event");
286 static int init(afb_api_t api)
288 struct navigation_state *ns;
291 ns = g_try_malloc0(sizeof(*ns));
293 AFB_ERROR("out of memory allocating navigation state");
297 rc = afb_daemon_require_api("vshl-capabilities", 1);
299 const char **tmp = vshl_capabilities_events;
300 json_object *args = json_object_new_object();
301 json_object *actions = json_object_new_array();
304 json_object_array_add(actions, json_object_new_string(*tmp++));
306 json_object_object_add(args, "actions", actions);
307 if(json_object_array_length(actions)) {
308 rc = afb_api_call_sync(api, "vshl-capabilities", "navigation/subscribe",
309 args, NULL, NULL, NULL);
311 AFB_WARNING("afb_api_call_sync returned %d", rc);
313 json_object_put(args);
316 AFB_WARNING("unable to initialize vshl-capabilities binding");
319 ns->status_event = afb_daemon_make_event("status");
320 ns->position_event = afb_daemon_make_event("position");
321 ns->waypoints_event = afb_daemon_make_event("waypoints");
323 if (!afb_event_is_valid(ns->status_event) ||
324 !afb_event_is_valid(ns->position_event) ||
325 !afb_event_is_valid(ns->waypoints_event)) {
326 AFB_ERROR("Cannot create events");
330 afb_api_set_userdata(api, ns);
333 g_rw_lock_init(&ns->rw_lock);
338 static const afb_verb_t binding_verbs[] = {
341 .callback = subscribe,
342 .info = "Subscribe to event"
344 .verb = "unsubscribe",
345 .callback = unsubscribe,
346 .info = "Unsubscribe to event"
348 .verb = "broadcast_status",
349 .callback = broadcast_status,
350 .info = "Allows clients to broadcast status events"
352 .verb = "broadcast_position",
353 .callback = broadcast_position,
354 .info = "Broadcast out position event"
356 .verb = "broadcast_waypoints",
357 .callback = broadcast_waypoints,
358 .info = "Broadcast out waypoint event"
364 * description of the binding for afb-daemon
366 const afb_binding_t afbBindingV3 = {
368 .verbs = binding_verbs,