--- /dev/null
+<html>
+<h1>Hello, Tizen Vehicle API!</h1>
+
+<body>
+<pre id="console"></pre>
+<script src="js/js-test-pre.js"></script>
+<script>
+
+debug('tizen.vehicle.vehicleSpeed ' + tizen.vehicle.vehicleSpeed);
+debug('tizen.vehicle.vehicleSpeed.zones ' + tizen.vehicle.vehicleSpeed.zones);
+
+tizen.vehicle.vehicleSpeed.get().then(function(vehicleSpeed) {
+ debug("Vehicle speed: " + vehicleSpeed.speed);
+},
+function(error) {
+ debug("There was an error");
+});
+
+</script>
+<script src="js/js-test-post.js"></script>
+</body>
+</html>
BuildRequires: pkgconfig(capi-system-sensor)
BuildRequires: pkgconfig(capi-system-system-settings)
BuildRequires: pkgconfig(libtzplatform-config)
+%if "%{profile}" == "ivi"
+BuildRequires: pkgconfig(automotive-message-broker)
+%endif
# For IVI, it doesn't need sim package.
%if "%{profile}" == "mobile"
BuildRequires: pkgconfig(capi-telephony-sim)
'callhistory/callhistory.gyp:*',
],
}],
+ [ 'extension_host_os == "ivi"', {
+ 'dependencies': [
+ 'vehicle/vehicle.gyp:*',
+ ],
+ }],
],
},
{
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vehicle/vehicle.h"
+
+#include <abstractpropertytype.h>
+#include <debugout.h>
+#include <gio/gio.h>
+#include <glib.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+
+#include "common/extension.h"
+#include "common/picojson.h"
+
+namespace {
+
+template<typename T> struct traits;
+
+template<>
+struct traits<GVariant> {
+ struct delete_functor {
+ void operator()(GVariant * p) const {
+ if (p != nullptr)
+ g_variant_unref(p);
+ }
+ };
+};
+
+template<>
+struct traits<GError> {
+ struct delete_functor {
+ void operator()(GError * p) const {
+ if (p != nullptr)
+ g_error_free(p);
+ }
+ };
+};
+
+template<>
+struct traits<GDBusProxy> {
+ struct delete_functor {
+ void operator()(GDBusProxy * p) const {
+ if (p != nullptr)
+ g_object_unref(p);
+ }
+ };
+};
+
+template<>
+struct traits<GVariantIter> {
+ struct delete_functor {
+ void operator()(GVariantIter * p) const {
+ if (p != nullptr)
+ g_variant_iter_free(p);
+ }
+ };
+};
+
+template<>
+struct traits<gchar> {
+ struct delete_functor {
+ void operator()(gchar * p) const {
+ if (p != nullptr)
+ g_free(p);
+ }
+ };
+};
+
+template<typename T> using super_ptr =
+ ::std::unique_ptr<T, typename traits<T>::delete_functor>;
+
+template<typename T> super_ptr<T> make_super(T* t) {
+ return super_ptr<T>(t);
+}
+
+void PostReply(Vehicle::CallbackInfo* cb_obj, picojson::object object) {
+ picojson::object msg;
+
+ msg["method"] = picojson::value(cb_obj->method);
+ msg["asyncCallId"] = picojson::value(cb_obj->callback_id);
+ msg["value"] = picojson::value(object);
+
+ std::string message = picojson::value(msg).serialize();
+
+ DebugOut() << "Reply message: " << message << endl;
+
+ cb_obj->instance->PostMessage(message.c_str());
+}
+
+void PostError(Vehicle::CallbackInfo* cb_obj, std::string error) {
+ picojson::object msg;
+ msg["method"] = picojson::value(cb_obj->method);
+ msg["error"] = picojson::value(true);
+ msg["value"] = picojson::value(error);
+ msg["asyncCallId"] =
+ picojson::value(static_cast<double>(cb_obj->callback_id));
+
+ std::string message = picojson::value(msg).serialize();
+
+ DebugOut() << "Error Reply message: " << message << endl;
+
+ cb_obj->instance->PostMessage(message.c_str());
+}
+
+picojson::value GetBasic(GVariant* value) {
+ std::string type = g_variant_get_type_string(value);
+ picojson::value v;
+
+ if (type == "i") {
+ v = picojson::value(static_cast<double>(GVS<int>::value(value)));
+ } else if (type == "d") {
+ v = picojson::value(GVS<double>::value(value));
+ } else if (type == "q") {
+ v = picojson::value(static_cast<double>(GVS<uint16_t>::value(value)));
+ } else if (type == "n") {
+ v = picojson::value(static_cast<double>(GVS<int16_t>::value(value)));
+ } else if (type == "y") {
+ v = picojson::value(static_cast<double>(GVS<char>::value(value)));
+ } else if (type == "u") {
+ v = picojson::value(static_cast<double>(GVS<uint32_t>::value(value)));
+ } else if (type == "x") {
+ v = picojson::value(static_cast<double>(GVS<int64_t>::value(value)));
+ } else if (type == "t") {
+ v = picojson::value(static_cast<double>(GVS<uint64_t>::value(value)));
+ } else if (type == "b") {
+ v = picojson::value(GVS<bool>::value(value));
+ }
+
+ return v;
+}
+
+void AsyncCallback(GObject* source, GAsyncResult* res, gpointer user_data) {
+ debugOut("GetAll() method call completed");
+
+ Vehicle::CallbackInfo *cb_obj =
+ static_cast<Vehicle::CallbackInfo*>(user_data);
+
+ if (!cb_obj) {
+ debugOut("invalid cb object");
+ return;
+ }
+
+ GError* error = nullptr;
+
+ auto property_map = make_super(
+ g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error));
+
+ auto error_ptr = make_super(error);
+
+ if (error_ptr) {
+ DebugOut() << "failed to call GetAll on interface: "
+ << error_ptr->message << endl;
+ PostError(cb_obj, "unknown");
+ delete cb_obj;
+ return;
+ }
+
+ GVariantIter* iter;
+ gchar* key;
+ GVariant* value;
+
+ g_variant_get(property_map.get(), "(a{sv})", &iter);
+
+ auto iter_ptr = make_super(iter);
+
+ std::map<std::string, GVariant*> return_value;
+
+ while (g_variant_iter_next(iter_ptr.get(), "{sv}", &key, &value)) {
+ return_value[key] = value;
+ g_free(key);
+ }
+
+ picojson::value::object object;
+
+ for (auto itr = return_value.begin(); itr != return_value.end(); itr++) {
+ std::string key = (*itr).first;
+
+ /// make key lowerCamelCase:
+ std::transform(key.begin(), key.begin() + 1, key.begin(), ::tolower);
+
+ auto variant = make_super((*itr).second);
+ picojson::value v = GetBasic(variant.get());
+ object[key] = v;
+ }
+
+ PostReply(cb_obj, object);
+ delete cb_obj;
+}
+
+} // namespace
+
+Vehicle::Vehicle(common::Instance* instance)
+ : main_loop_(g_main_loop_new(0, FALSE)),
+ thread_(Vehicle::SetupMainloop, this),
+ instance_(instance) {
+ thread_.detach();
+}
+
+Vehicle::~Vehicle() {
+ g_main_loop_quit(main_loop_);
+ g_main_loop_unref(main_loop_);
+}
+
+void Vehicle::Get(const std::string& property, Zone::Type zone, double ret_id) {
+ CallbackInfo * data = new CallbackInfo;
+
+ data->callback_id = ret_id;
+ data->method = "get";
+ data->instance = instance_;
+
+ std::string obj_pstr = FindProperty(property, zone);
+
+ if (obj_pstr.empty()) {
+ debugOut("could not find property " + property);
+ PostError(data, "invalid_operation");
+ return;
+ }
+
+ debugOut("Getting properties interface");
+
+ GError* error = nullptr;
+
+ auto properties_proxy = make_super(
+ g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ "org.automotive.message.broker",
+ obj_pstr.c_str(),
+ "org.freedesktop.DBus.Properties",
+ NULL,
+ &error));
+
+ auto error_ptr = make_super(error);
+
+ if (error_ptr) {
+ debugOut("failed to get properties proxy");
+ return;
+ }
+
+ std::string interfaceName = "org.automotive." + property;
+
+ debugOut("Calling GetAll");
+
+ g_dbus_proxy_call(properties_proxy.get(),
+ "GetAll",
+ g_variant_new("(s)", interfaceName.c_str()),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+ AsyncCallback, data);
+}
+
+std::string Vehicle::FindProperty(const std::string& object_name, int zone) {
+ auto manager_proxy = make_super(GetAutomotiveManager());
+
+ if (!manager_proxy) {
+ return "";
+ }
+
+ GError* error(nullptr);
+
+ auto object_path_variant = make_super(
+ g_dbus_proxy_call_sync(manager_proxy.get(),
+ "FindObjectForZone",
+ g_variant_new("(si)",
+ object_name.c_str(),
+ zone),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error));
+
+ auto error_ptr = make_super(error);
+
+ if (error_ptr) {
+ DebugOut() << "error calling FindObjectForZone: "
+ << error_ptr->message << endl;
+
+ DebugOut() << "Could not find object in zone: " << zone << endl;
+ return "";
+ }
+
+ if (!object_path_variant) {
+ DebugOut() << "Could not find object in zone: " << zone << endl;
+ return "";
+ }
+
+ gchar* obj_path = nullptr;
+ g_variant_get(object_path_variant.get(), "(o)", &obj_path);
+
+ auto obj_path_ptr = make_super(obj_path);
+
+ DebugOut() << "FindObjectForZone() returned object path: " <<
+ obj_path_ptr.get() << endl;
+
+ return obj_path;
+}
+
+GDBusProxy* Vehicle::GetAutomotiveManager() {
+ GError* error = nullptr;
+ GDBusProxy* am =
+ g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ "org.automotive.message.broker",
+ "/",
+ "org.automotive.Manager",
+ NULL,
+ &error);
+
+ auto error_ptr = make_super(error);
+
+ if (error_ptr) {
+ DebugOut() << "error calling GetAutomotiveManager: "
+ << error_ptr->message << endl;
+ }
+
+ return am;
+}
+
+void Vehicle::SetupMainloop(void *data) {
+ Vehicle* self = reinterpret_cast<Vehicle*>(data);
+ GMainContext* ctx = g_main_context_default();
+
+ g_main_context_push_thread_default(ctx);
+ g_main_loop_run(self->main_loop_);
+}
--- /dev/null
+{
+ 'includes':[
+ '../common/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'tizen_vehicle',
+ 'type': 'loadable_module',
+ 'variables': {
+ 'packages': [
+ 'automotive-message-broker',
+ 'icu-i18n',
+ 'gio-2.0',
+ 'gio-unix-2.0',
+ ],
+ },
+ 'includes': [
+ '../common/pkg-config.gypi',
+ ],
+ 'sources': [
+ 'vehicle.cc',
+ 'vehicle.h',
+ 'vehicle_api.js',
+ 'vehicle_extension.cc',
+ 'vehicle_extension.h',
+ 'vehicle_instance.cc',
+ 'vehicle_instance.h',
+ ],
+ 'conditions': [
+ [ 'tizen == 1', {
+ 'variables': { 'packages': ['vconf'] },
+ }],
+ ],
+ },
+ ],
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VEHICLE_VEHICLE_H_
+#define VEHICLE_VEHICLE_H_
+
+#include <abstractpropertytype.h>
+#include <gio/gio.h>
+#include <glib.h>
+
+#include <string>
+#include <thread> // NOLINT
+
+#include "common/picojson.h"
+
+namespace common {
+
+class Instance;
+
+} // namespace common
+
+typedef std::function<void (picojson::object)> GetReply;
+typedef std::function<void (std::string)> ErrorReply;
+
+class Vehicle {
+ public:
+ struct CallbackInfo {
+ std::string method;
+ common::Instance* instance;
+ double callback_id;
+ };
+
+ explicit Vehicle(common::Instance* i);
+ ~Vehicle();
+
+ void Get(const std::string& property, Zone::Type zone, double ret_id);
+
+ private:
+ std::string FindProperty(const std::string& object_name, int zone);
+ GDBusProxy* GetAutomotiveManager();
+
+ static void SetupMainloop(void *data);
+ GMainLoop* main_loop_;
+ std::thread thread_;
+ common::Instance* instance_;
+};
+
+#endif // VEHICLE_VEHICLE_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var next_async_call_id = 0;
+var async_calls = {};
+
+function VehicleInterface(attname) {
+ this.attributeName = attname;
+
+ var msg = {};
+ msg['method'] = 'zones';
+ msg['name'] = this.attributeName;
+
+ this._zones = [];
+
+ var call = new AsyncCall(function(data) {
+ this._zones = data;
+ });
+
+ async_calls[next_async_call_id] = call;
+ ++next_async_call_id;
+
+ extension.postMessage(JSON.stringify(msg));
+
+ Object.defineProperty(this, 'zones', { get: function() { return this._zones } });
+}
+
+VehicleInterface.prototype.get = function(zone) {
+ var msg = {};
+ msg['method'] = 'get';
+ msg['name'] = this.attributeName;
+ msg['zone'] = zone;
+
+ return createPromise(msg);
+};
+
+function AsyncCall(resolve, reject) {
+ this.resolve = resolve;
+ this.reject = reject;
+}
+
+function createPromise(msg) {
+ var promise = new Promise(function(resolve, reject) {
+ async_calls[next_async_call_id] = new AsyncCall(resolve, reject);
+ });
+
+ msg.asyncCallId = next_async_call_id;
+ extension.postMessage(JSON.stringify(msg));
+ ++next_async_call_id;
+ return promise;
+}
+
+function _defineVehicleProperty(obj, prop) {
+ Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleInterface(prop) });
+}
+
+extension.setMessageListener(function(json) {
+ var msg = JSON.parse(json);
+
+ console.log('message received: ' + msg);
+
+ switch (msg.method) {
+ case 'get':
+ handleGetReply(msg);
+ break;
+ case 'zones':
+ handleZonesReply(msg);
+ break;
+ }
+});
+
+function handleGetReply(msg) {
+ console.log('handle get reply');
+
+ var cbobj = async_calls[msg.asyncCallId];
+
+ if (msg.error)
+ cbobj.reject(msg.value);
+ else
+ cbobj.resolve(msg.value);
+
+ delete async_calls[msg.asyncCallId];
+}
+
+function handleZonesReply(msg) {
+ var cbobj = async_calls[msg.asyncCallId];
+
+ if (cbobj)
+ cbobj.resolve(msg.value);
+}
+
+_defineVehicleProperty(exports, 'vehicleSpeed');
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vehicle/vehicle_extension.h"
+
+#include "vehicle/vehicle_instance.h"
+
+common::Extension* CreateExtension() {
+ return new VehicleExtension();
+}
+
+extern const char kSource_vehicle_api[];
+
+VehicleExtension::VehicleExtension() {
+ SetExtensionName("tizen.vehicle");
+ SetJavaScriptAPI(kSource_vehicle_api);
+}
+
+VehicleExtension::~VehicleExtension() {
+}
+
+common::Instance* VehicleExtension::CreateInstance() {
+ return new VehicleInstance;
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VEHICLE_VEHICLE_EXTENSION_H_
+#define VEHICLE_VEHICLE_EXTENSION_H_
+
+#include "common/extension.h"
+
+class VehicleExtension : public common::Extension {
+ public:
+ VehicleExtension();
+ virtual ~VehicleExtension();
+
+ private:
+ // common::Extension implementation.
+ virtual common::Instance* CreateInstance();
+};
+
+#endif // VEHICLE_VEHICLE_EXTENSION_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vehicle/vehicle_instance.h"
+
+#include <abstractpropertytype.h>
+
+#include <algorithm>
+#include <string>
+
+#include "vehicle/vehicle.h"
+
+VehicleInstance::VehicleInstance(): vehicle_(new Vehicle(this)) {
+ DebugOut::setDebugThreshhold(5);
+}
+
+void VehicleInstance::HandleMessage(const char* message) {
+ DebugOut() << "VehicleInstance message received " << message << endl;
+
+ picojson::value v;
+
+ std::string err;
+ picojson::parse(v, message, message + strlen(message), &err);
+ if (!err.empty()) {
+ return;
+ }
+
+ std::string method = v.get("method").to_str();
+
+ if (method == "get") {
+ std::string attribute = v.get("name").to_str();
+ int callback_id = v.get("asyncCallId").get<double>();
+ Zone::Type amb_zone = 0;
+ if (v.contains("zone")) {
+ picojson::value zone = v.get("zone");
+ picojson::array zones = zone.get("value").get<picojson::array>();
+ amb_zone = ZoneToAMBZone(zones);
+ }
+
+ std::transform(attribute.begin(), attribute.begin() + 1, attribute.begin(),
+ ::toupper);
+
+ vehicle_->Get(attribute, amb_zone, callback_id);
+ }
+}
+
+void VehicleInstance::HandleSyncMessage(const char* message) {
+}
+
+int VehicleInstance::ZoneToAMBZone(picojson::array zones) {
+ Zone::Type amb_zone = 0;
+
+ for (auto zone : zones) {
+ std::string tempzone = zone.to_str();
+
+ if (tempzone == "Front") {
+ amb_zone |= Zone::Front;
+ } else if (tempzone == "Middle") {
+ amb_zone |= Zone::Middle;
+ } else if (tempzone == "Right") {
+ amb_zone |= Zone::Right;
+ } else if (tempzone == "Left") {
+ amb_zone |= Zone::Left;
+ } else if (tempzone == "Rear") {
+ amb_zone |= Zone::Rear;
+ } else if (tempzone == "Center") {
+ amb_zone |= Zone::Center;
+ }
+ }
+
+ return amb_zone;
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VEHICLE_VEHICLE_INSTANCE_H_
+#define VEHICLE_VEHICLE_INSTANCE_H_
+
+#include "common/extension.h"
+#include "common/picojson.h"
+#include "vehicle/vehicle.h"
+
+class VehicleInstance : public common::Instance {
+ public:
+ VehicleInstance();
+ virtual ~VehicleInstance() {}
+
+ private:
+ // common::Instance implementation.
+ virtual void HandleMessage(const char* msg);
+ virtual void HandleSyncMessage(const char* msg);
+
+ int ZoneToAMBZone(picojson::array);
+
+ Vehicle* vehicle_;
+};
+
+#endif // VEHICLE_VEHICLE_INSTANCE_H_