diff options
author | Kevron Rees <tripzero.kev@gmail.com> | 2014-11-05 17:29:07 -0800 |
---|---|---|
committer | Kevron Rees <tripzero.kev@gmail.com> | 2014-11-05 17:29:07 -0800 |
commit | 687123b5f7fa7a4b172606583ad378452757b28b (patch) | |
tree | 83819285f1329172204636aee39c4adc8342908f | |
parent | 5051c66de77c5e939c141c90056120c694446696 (diff) | |
parent | 7f96771b09f0bc66c2d2c3a5a5c9cef9b2eea4c2 (diff) | |
download | automotive-message-broker-687123b5f7fa7a4b172606583ad378452757b28b.tar.gz |
Merge pull request #28 from tripzero/master0.12.800
xwalk vehicle extension, fixes from 0.12 ported, more w3C vehicle data spec support.
50 files changed, 4302 insertions, 368 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b29475e2..a91fcf0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,9 +6,9 @@ set(CMAKE_BUILD_TYPE, Debug) include(FindPkgConfig) set(PROJECT_NAME "automotive-message-broker") -set(PROJECT_VERSION "0.11.903") -set(PROJECT_CODENAME "veyron") -set(PROJECT_QUALITY "beta") +set(PROJECT_VERSION "0.12.800") +set(PROJECT_CODENAME "agera") +set(PROJECT_QUALITY "alpha") add_definitions(-DPROJECT_VERSION="${PROJECT_VERSION}") add_definitions(-DPROJECT_NAME="${PROJECT_NAME}") @@ -40,6 +40,8 @@ option(cangen_plugin "Can generator plugin" OFF) option(enable_icecc "Enable icecc checking, for distributed compilation" ON) option(enable_docs "enable Doxygen doc generation" OFF) option(usebluez5 "use bluez 5 API" OFF) +option(xwalk_vehicle_extension "Crosswalk vehicle extension" OFF) +set(XWALK_EXTENSION_PATH "/automotive-message-broker/xwalk" CACHE PATH "directory the xwalk extension will be installed to") #turn on -fpic/-fpie: set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -151,3 +153,4 @@ add_subdirectory(plugins) add_subdirectory(docs) add_subdirectory(tests) add_subdirectory(examples) +add_subdirectory(xwalk) diff --git a/ambd/main.cpp b/ambd/main.cpp index 5c6bb9d1..6d91e5b0 100644 --- a/ambd/main.cpp +++ b/ambd/main.cpp @@ -37,7 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include <QCoreApplication> -#else +#else #include <glib.h> @@ -54,7 +54,7 @@ void interrupt(int sign) { signal(sign, SIG_IGN); cout<<"Signal caught. Exiting gracefully.\n"<<endl; - + /// this will cause the application to terminate and clean up: delete mainloop; } @@ -83,7 +83,7 @@ void printVersion() DebugOut(0)<<"Version: "<<PROJECT_VERSION<<" ( "<<PROJECT_CODENAME<<" "<<PROJECT_QUALITY<<" )"<<endl; } -int main(int argc, char **argv) +int main(int argc, char **argv) { bool isdeamonize=false; @@ -100,7 +100,7 @@ int main(int argc, char **argv) case 'D': isdeamonize = true; break; - + case 'v': printVersion(); return (0); @@ -129,10 +129,10 @@ int main(int argc, char **argv) break; } } - + if(isdeamonize) daemonize(); - + if(!logfn.empty()) { logfile.open(logfn, ios::out | ios::trunc); @@ -151,14 +151,14 @@ int main(int argc, char **argv) #endif VehicleProperty::factory(); - + PluginLoader loader(config, argc, argv); - + if(!loader.sources().size()) { throw std::runtime_error("No sources present. aborting"); } - + mainloop = loader.mainloop(); /* Register signal handler */ @@ -166,8 +166,6 @@ int main(int argc, char **argv) signal(SIGTERM, interrupt); mainloop->exec(); - - VehicleProperty::shutdown(); if(logfile.is_open()) logfile.close(); diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 4a2af488..69e99af3 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -3,4 +3,7 @@ if(enable_docs) install (DIRECTORY dbus DESTINATION ${DOC_INSTALL_DIR} COMPONENT Docs) install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/amb.idl DESTINATION ${DOC_INSTALL_DIR}/dbus/html/ COMPONENT Docs) add_custom_target(doc_idl ALL mkdir -p ${CMAKE_CURRENT_SOURCE_DIR}/dbus/html/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/amb.idl ${CMAKE_CURRENT_SOURCE_DIR}/dbus/html/amb.idl WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Moving amb.idl" VERBATIM) + + configure_file (${CMAKE_CURRENT_SOURCE_DIR}/amb.idl ${CMAKE_CURRENT_SOURCE_DIR}/amb.idl @ONLY) + endif(enable_docs) diff --git a/docs/amb.idl b/docs/amb.idl index 35a7cc5f..941ae7eb 100644 --- a/docs/amb.idl +++ b/docs/amb.idl @@ -110,7 +110,9 @@ interface org.automotive.Manager { * except that it takes an addition zone argument and only returns the path for that zone. * \arg String property is the requested property to be retrieved. * \arg Zone zone is the zone which the object - * \returns string representing the DBus Object path + * \returns string representing the DBus Object path. Possible errors: + * "org.automotive.Manager.InvalidZone" + * "org.automotive.Manager.ObjectNotFound" */ method FindObjectForZone { in { @@ -197,19 +199,19 @@ interface org.automotive.TripMeter extends VehiclePropertyType { interface org.automotive.Acceleration extends VehiclePropertyType { /*! X - * \brief Must return acceleration on the "X" axis as 1/1000 G (gravitational force). + * \brief return acceleration on the "X" axis (Unit: centimeters per second squared) */ - attribute UInt16 X readonly + attribute Int16 X readonly /*! Y - * \brief Must return acceleration on the "Y" axis as 1/1000 G (gravitational force). + * \brief return acceleration on the "Y" axis (Unit: centimeters per second squared) */ - attribute UInt16 Y readonly + attribute Int16 Y readonly /*! Z - * \brief Must return acceleration on the "Z" axis as 1/1000 G (gravitational force). + * \brief return acceleration on the "Z" axis (Unit: centimeters per second squared) */ - attribute UInt16 Z readonly + attribute Int16 Z readonly } enumeration TransmissionMode { @@ -222,7 +224,7 @@ enumeration TransmissionMode { } /*! TransmissionPosition - * \brief Describes Transmission Pistion. Deprecated. Will disappear in 0.13 + * \brief Describes Transmission Pistion. Deprecated. Will disappear in 0.14 */ enumeration TransmissionPosition { Neutral = 0, @@ -278,7 +280,7 @@ interface org.automotive.Transmission extends VehiclePropertyType { interface org.automotive.CruiseControlStatus extends VehiclePropertyType { /*! Activated - * \brief Must return whether or not the Cruise Control system is active (true) or inactive (false) + * \brief Must return whether or not the Cruise Control system is active (true) or inactive (false). Depricated. Remove in 0.14. Use "Status" */ attribute Boolean Activated readonly @@ -286,10 +288,15 @@ interface org.automotive.CruiseControlStatus extends VehiclePropertyType { * \brief Must return target Cruise Control speed in kilometers per hour (kph). */ attribute UInt16 Speed readonly + + /*! Status + * \brief Must return whether or not the Cruise Control system is active (true) or inactive (false). + */ + attribute Boolean Status readonly } /*! - * Deprecated. Use BrakeOperation. Remove in 0.13 + * Deprecated. Use BrakeOperation. Remove in 0.14 */ interface org.automotive.WheelBrake extends VehiclePropertyType { @@ -312,71 +319,76 @@ interface org.automotive.LightStatus extends VehiclePropertyType { /*! Head * \brief Must return headlight status: on = true, off = false. */ - attribute Boolean Head readonly + attribute Boolean Head /*! RightTurn * \brief Must return right turn signal status: on = true, off = false. */ - attribute Boolean RightTurn readonly + attribute Boolean RightTurn /*! LeftTurn * \brief Must return left turn signal status: on = true, off = false. */ - attribute Boolean LeftTurn readonly + attribute Boolean LeftTurn /*! Brake * \brief Must return brake signal light status: on = true, off = false. */ - attribute Boolean Brake readonly + attribute Boolean Brake /*! Fog * \brief Must return fog light status: on = true, off = false. */ - attribute Boolean Fog readonly + attribute Boolean Fog /*! Hazard * \brief Must return hazard light status: on = true, off = false. */ - attribute Boolean Hazard readonly + attribute Boolean Hazard /*! Parking * \brief Must return parking light status: on = true, off = false. */ - attribute Boolean Parking readonly + attribute Boolean Parking /*! HighBeam * \brief Must return high beam status: on = true, off = false. */ - attribute Boolean HighBeam readonly + attribute Boolean HighBeam /*! AutomaticHeadlights * \brief Must return automatic headlight status: on = true, off = false. */ - attribute Boolean AutomaticHeadlights readonly + attribute Boolean AutomaticHeadlights /*! DynamicHighBeam * \brief Must return dynamic high beam status: on = true, off = false. */ - attribute Boolean DynamicHighBeam readonly + attribute Boolean DynamicHighBeam } interface org.automotive.InteriorLightStatus extends VehiclePropertyType { /*! Passenger - * \brief Must return passenger interior light status: on = true, off = false + * \brief Must return passenger interior light status: on = true, off = false. Deprecated. Remove in 0.14. Use status and zone. */ attribute Boolean Passenger readonly /*! Driver - * \brief Must return driver interior light status: on = true, off = false + * \brief Must return driver interior light status: on = true, off = false. Deprecated. Remove in 0.14. Use status and zone. */ attribute Boolean Driver readonly /*! Center - * \brief Must return center interior light status: on = true, off = false + * \brief Must return center interior light status: on = true, off = false. Deprecated. Remove in 0.14. Use status and zone. */ attribute Boolean Center readonly + + /*! Status + * \brief Must return interior light status for the zone. on = true, off = false + */ + attribute Boolean Status } @@ -426,29 +438,45 @@ interface org.automotive.Fuel extends VehiclePropertyType { */ attribute UInt32 FuelConsumedSinceRestart readonly; - /*! FuelConsumedSinceRestart - * \brief must return fuel consumed since engine start; (Unit: milliliters per 100 kilometers) resets to 0 each restart + /*! TimeSinceRestart + * \brief must return time elapsed since vehicle restart (Unit: seconds) */ - attribute UInt32 FuelConsumedSinceRestart readonly; + attribute UInt32 TimeSinceRestart readonly; } interface org.automotive.EngineOil extends VehiclePropertyType { /*! Remaining - * \brief Must return remaining engine oil as percentage of fullness. + * \brief Must return remaining engine oil as percentage of fullness. Deprecated. Remove in 0.14. Use "Level" */ attribute UInt16 Remaining readonly /*! Temperature - * \brief Must return Engine Oil Temperature in Celcius. + * \brief Must return Engine Oil Temperature in Celcius. */ attribute long Temperature readonly /*! Pressure - * \brief Must return Engine Oil Pressure in kPa. + * \brief Must return Engine Oil Pressure in kPa. */ attribute UInt16 Pressure readonly + + /*! Level + * \brief Must return engine oil level (Unit: percentage, 0%: empty, 100%: full + */ + attribute UInt16 Level readonly + + /*! Change + * \brief Must return engine oil change indicator status: change oil (true) or no change (false) + */ + attribute boolean Change readonly + + /*! LifeRemaining + * \brief Must return engine oil change indicator status: change oil (true) or no change (false) + */ + attribute boolean LifeRemaining readonly + } @@ -490,13 +518,13 @@ interface org.automotive.Temperature extends VehiclePropertyType { /*! Interior * \brief Must return the temperature of the interior of the vehicle in celcius. */ - /// Deprecated. Use InteriorTemperature. Remove in 0.13 + /// Deprecated. Use InteriorTemperature. Remove in 0.14 attribute signed short Interior readonly /*! Exterior * \brief Must return the temperature of the exterior of the vehicle in celcius. */ - /// Deprecated. Use ExteriorTemperature. Remove in 0.13 + /// Deprecated. Use ExteriorTemperature. Remove in 0.14 attribute signed short Exterior readonly /*! Interior @@ -532,7 +560,7 @@ interface org.automotive.WindshieldWiper extends VehiclePropertyType { attribute UInt16 WindshieldWiper readonly } -/*! Deprecated. Use ClimateControl interface. Remove in 0.13 +/*! Deprecated. Use ClimateControl interface. Remove in 0.14 */ interface org.automotive.HVAC extends VehiclePropertyType { const UInt16 AIRFLOWDIRECTION_FRONTPANEL = 0; @@ -651,7 +679,7 @@ interface org.automotive.WindowStatus extends VehiclePropertyType { /*! Defrost * \brief Must return the defroster status of the window. On = true, Off = false. - * Deprecated. Use Defrost interface. Remove in 0.13. + * Deprecated. Use Defrost interface. Remove in 0.14. */ attribute Boolean Defrost; } @@ -807,7 +835,7 @@ interface org.automotive.Odometer extends VehiclePropertyType { /*! Odometer * \brief MUST return Distance traveled in km */ - /// Deprecated. Use DistanceTotal. Remove in 0.13 + /// Deprecated. Use DistanceTotal. Remove in 0.14 attribute UInt32 Odometer readonly /*! DistnaceTotal @@ -841,7 +869,7 @@ interface org.automotive.Fluid extends VehiclePropertyType { attribute UInt16 Washer readonly } -/// Deprecated. Use BatteryStatus. Remove in 0.13 +/// Deprecated. Use BatteryStatus. Remove in 0.14 interface org.automotive.Battery extends VehiclePropertyType { /*! Voltage @@ -901,7 +929,7 @@ interface org.automotive.SecurityAlert extends VehiclePropertyType { attribute Boolean SecurityAlert readonly } -/// Deprecated. Use LightStatus. remove in 0.13 +/// Deprecated. Use LightStatus. remove in 0.14 interface org.automotive.ParkingBrake extends VehiclePropertyType { /*! ParkingBrake @@ -910,7 +938,7 @@ interface org.automotive.ParkingBrake extends VehiclePropertyType { attribute Boolean ParkingBrake readonly } -/// Deprecated. Use LightStatus. remove in 0.13 +/// Deprecated. Use LightStatus. remove in 0.14 interface org.automotive.ParkingLight extends VehiclePropertyType { /*! ParkingLight @@ -919,7 +947,7 @@ interface org.automotive.ParkingLight extends VehiclePropertyType { attribute Boolean ParkingLight readonly } -/// Deprecated. Use LightStatus. remove in 0.13 +/// Deprecated. Use LightStatus. remove in 0.14 interface org.automotive.HazardLight extends VehiclePropertyType { /*! HazardLight @@ -975,7 +1003,7 @@ enumeration AirbagStatus { } /*! - * Deprecated. Use "Door". Remove in 0.13 + * Deprecated. Use "Door". Remove in 0.14 */ interface org.automotive.DoorStatus extends VehiclePropertyType { @@ -1060,7 +1088,7 @@ interface org.automotive.NightMode extends VehiclePropertyType { /*! * \brief MUST return whether or not the system is in NightMode or not. True = Night time, False = Day time - * Deprecated. Will be removed in 0.13. Use "Mode" + * Deprecated. Will be removed in 0.14. Use "Mode" */ attribute Boolean NightMode readonly @@ -1253,12 +1281,101 @@ interface org.automotive.EngineCoolant extends VehiclePropertyType { /*! * \brief MUST return engine coolant level (Unit: percentage 0%: empty, 100%: full) */ - attribute Uint8 Level readonly + attribute Uint16 Level readonly /*! * \brief MUST return engine coolant temperature (Unit: celcius) */ - attribute Uint8 Temperature readonly + attribute Int16 Temperature readonly +} + +interface org.automotive.PowertrainTorque extends VehiclePropertyType { + + /*! + * \brief must return powertrain torque (Unit: newton meters) + */ + attribute UInt16 Value readonly +} + +interface org.automotive.AcceleratorPedalPosition extends VehiclePropertyType { + + /*! + * \brief must return accelerator pedal position as a percentage (Unit: percentage, 0%: released pedal, 100%: fully depressed) + */ + attribute UInt8 Value readonly +} + +interface org.automotive.WheelTick extends VehiclePropertyType { + + /*! + * \brief must return number of ticks per second (Unit: ticks per second) + */ + attribute UInt8 Value readonly +} + +interface IgnitionTime : VehicleCommonDataType { + /*! + * \brief must return time at ignition on + */ + attribute UInt64 ignitionOnTime readonly + + /*! + * \brief must return time at ignition off + */ + attribute UInt64 ignitionOffTime readonly +}; + +interface org.automotive.YawRate extends VehiclePropertyType { + + /*! + * \brief must return yaw rate of vehicle. (Unit: degrees per second) + */ + attribute Int16 Value readonly +} + +interface org.automotive.BrakeOperation extends VehiclePropertyType { + + /*! + * \brief must return whether brake pedal is depressed or not. true: brake pedal is depressed, false: brake pedal is not depressed + */ + attribute Boolean BrakePedalDepressed readonly +} + +enum VehicleButton { + home = "home", + back = "back", + search = "search", + call = "call", + end_call = "end_call", + media_play = "media_play", + media_next = "media_next", + media_previous = "media_previous", + media_pause = "media_pause", + voice_recognize = "voice_recognize", + enter = "enter", + left = "left", + right = "right", + up = "up", + down = "down" +} + +enum PressType { + press = "press", + long_press = "long_press", + release = "release" +}; + +interface org.automotive.ButtonEvent extends VehiclePropertyType { + + /*! + * \brief must return the button events tha occured. This supports multiple simultanious button events. + */ + attribute array Button of VehicleButton readonly + + /*! + * \brief must return the type of event + */ + attribute PressType State readonly } } diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4d68156a..28ff5a33 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -16,6 +16,7 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/qtmainloopconfig.in ${CMAKE_CURRENT_ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/websocketsink2.in ${CMAKE_CURRENT_SOURCE_DIR}/websocketsink2 @ONLY) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/websocketsource2.in ${CMAKE_CURRENT_SOURCE_DIR}/websocketsource2 @ONLY) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/testsourceconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/testsourceconfig @ONLY) +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cangenconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/cangenconfig @ONLY) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/bluemonkey/bluemonkeyconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/bluemonkey/bluemonkeyconfig @ONLY) install (FILES ${amb_examples} DESTINATION /etc/ambd/examples) diff --git a/examples/cangenconfig b/examples/cangenconfig.in index 816c74e6..81add2cb 100644 --- a/examples/cangenconfig +++ b/examples/cangenconfig.in @@ -2,18 +2,18 @@ "sources" : [ { "name" : "CANSimPlugin", - "path":"/usr/lib/automotive-message-broker/cansimplugin.so", + "path":"@PLUGIN_INSTALL_PATH@/cansimplugin.so", "interfaces" : ["vcan0", "vcan1"] }, { "name" : "CANGenPlugin", - "path":"/usr/lib/automotive-message-broker/cangenplugin.so" + "path":"@PLUGIN_INSTALL_PATH@/cangenplugin.so" } ], "sinks": [ { "name" : "DBusSink", - "path" : "/usr/lib/automotive-message-broker/dbussinkplugin.so", + "path" : "@PLUGIN_INSTALL_PATH@/dbussinkplugin.so", "frequency" : "60" } diff --git a/examples/databasesource.in b/examples/databasesource.in index ccfa4915..69ab8cb9 100644 --- a/examples/databasesource.in +++ b/examples/databasesource.in @@ -4,7 +4,7 @@ "name" : "Database Source", "path" : "@PLUGIN_INSTALL_PATH@/databasesinkplugin.so", "playbackOnLoad" : "true", - "databaseFile" : "generated.db" + "databaseFile" : "/tmp/storage" } ], "sinks": [ diff --git a/examples/opencvdbusconfig.in b/examples/opencvdbusconfig.in index 0ee79402..a3743987 100644 --- a/examples/opencvdbusconfig.in +++ b/examples/opencvdbusconfig.in @@ -5,14 +5,16 @@ "name" : "OpenCV LUX", "path" : "@PLUGIN_INSTALL_PATH@/opencvluxplugin.so", "threaded" : "true", - "cuda" : "true", + "cuda" : "false", + "opencl" : "true", "fps" : "30", "pixelLowerBound" : "18", "pixelUpperBound" : "255", "device" : "0", "codec" : "divx", "logging" : "true", - "logfile" : "/tmp/video.avi" + "logfile" : "/tmp/video.avi", + "ddd" : "true" }, { "path" : "@PLUGIN_INSTALL_PATH@/examplesourceplugin.so" diff --git a/lib/abstractpropertytype.h b/lib/abstractpropertytype.h index c13cb41d..5b7128e0 100644 --- a/lib/abstractpropertytype.h +++ b/lib/abstractpropertytype.h @@ -291,6 +291,22 @@ public: }; template <> +class GVS<uint8_t> +{ +public: + static const char* signature() { return "q"; } + + static uint16_t value(GVariant* v) + { + return g_variant_get_uint16(v); + } + static std::string stringize(std::string v) + { + return v; + } +}; + +template <> class GVS<uint16_t> { public: diff --git a/lib/superptr.hpp b/lib/superptr.hpp index 26e90878..c91a2c2f 100644 --- a/lib/superptr.hpp +++ b/lib/superptr.hpp @@ -60,6 +60,16 @@ struct traits<gchar> { }; }; +template <> +struct traits<GDBusConnection> { + struct delete_functor { + void operator()(GDBusConnection* p) const { + if (p != nullptr) + g_dbus_connection_close_sync(p, nullptr, nullptr); + } + }; +}; + template<typename T> using super_ptr = ::std::unique_ptr<T, typename traits<T>::delete_functor>; diff --git a/lib/vehicleproperty.cpp b/lib/vehicleproperty.cpp index 3573ce28..d4cd94c9 100644 --- a/lib/vehicleproperty.cpp +++ b/lib/vehicleproperty.cpp @@ -21,6 +21,7 @@ #include "listplusplus.h" #include "debugout.h" #include "mappropertytype.hpp" +#include "superptr.hpp" #include <map> @@ -34,7 +35,23 @@ using namespace std; std::map<VehicleProperty::Property, VehicleProperty::PropertyTypeFactoryCallback> VehicleProperty::registeredPropertyFactoryMap; -VehicleProperty* VehicleProperty::thereCanOnlyBeOne = nullptr; +std::unique_ptr<VehicleProperty> VehicleProperty::thereCanOnlyBeOne(nullptr); + +const char* ButtonEvents::W3C::Home = "home"; +const char* ButtonEvents::W3C::Back = "back"; +const char* ButtonEvents::W3C::Search = "search"; +const char* ButtonEvents::W3C::Call = "call"; +const char* ButtonEvents::W3C::EndCall = "end_call"; +const char* ButtonEvents::W3C::MediaPlay = "media_play"; +const char* ButtonEvents::W3C::MediaPause = "media_pause"; +const char* ButtonEvents::W3C::MediaPrevious = "media_previous"; +const char* ButtonEvents::W3C::MediaNext = "media_next"; +const char* ButtonEvents::W3C::VoiceRecognize = "voice_regocnize"; +const char* ButtonEvents::W3C::Enter = "enter"; +const char* ButtonEvents::W3C::Left = "left"; +const char* ButtonEvents::W3C::Right = "right"; +const char* ButtonEvents::W3C::Up = "up"; +const char* ButtonEvents::W3C::Down = "down"; const char* Transmission::W3C::Park = "park"; const char* Transmission::W3C::Reverse = "reverse"; @@ -82,6 +99,8 @@ const VehicleProperty::Property VehicleProperty::BatteryChargeLevel = "BatteryCh const VehicleProperty::Property VehicleProperty::InteriorTemperature = "InteriorTemperature"; const VehicleProperty::Property VehicleProperty::ExteriorTemperature = "ExteriorTemperature"; const VehicleProperty::Property VehicleProperty::EngineOilTemperature = "EngineOilTemperature"; +const VehicleProperty::Property VehicleProperty::EngineOilLifeRemaining = "EngineOilLifeRemaining"; +const VehicleProperty::Property VehicleProperty::EngineOilChangeIndicator= "EngineOilChangeIndicator"; const VehicleProperty::Property VehicleProperty::VIN = "VIN"; const VehicleProperty::Property VehicleProperty::WMI = "WMI"; const VehicleProperty::Property VehicleProperty::TirePressure = "TirePressure"; @@ -104,6 +123,7 @@ const VehicleProperty::Property VehicleProperty::LightDynamicHighBeam= "LightDyn const VehicleProperty::Property VehicleProperty::InteriorLightDriver = "InteriorLightDriver"; const VehicleProperty::Property VehicleProperty::InteriorLightCenter = "InteriorLightCenter"; const VehicleProperty::Property VehicleProperty::InteriorLightPassenger = "InteriorLightPassenger"; +const VehicleProperty::Property VehicleProperty::InteriorLightStatus = "InteriorLightStatus"; const VehicleProperty::Property VehicleProperty::EngineLoad = "EngineLoad"; const VehicleProperty::Property VehicleProperty::Horn = "Horn"; const VehicleProperty::Property VehicleProperty::FuelLevel = "FuelLevel"; @@ -192,6 +212,14 @@ const VehicleProperty::Property VehicleProperty::SeatPositionSideCushion = "Seat const VehicleProperty::Property VehicleProperty::DashboardIllumination = "DashboardIllumination"; const VehicleProperty::Property VehicleProperty::GeneratedVehicleSoundMode = "GeneratedVehicleSoundMode"; const VehicleProperty::Property VehicleProperty::DriverId = "DriverId"; +const VehicleProperty::Property VehicleProperty::PowertrainTorque = "PowertrainTorque"; +const VehicleProperty::Property VehicleProperty::AcceleratorPedalPosition = "AcceleratorPedalPosition"; +const VehicleProperty::Property VehicleProperty::Chime = "Chime"; +const VehicleProperty::Property VehicleProperty::WheelTick = "WheelTick"; +const VehicleProperty::Property VehicleProperty::IgnitionTimeOn = "IgnitionTimeOn"; +const VehicleProperty::Property VehicleProperty::IgnitionTimeOff = "IgnitionTimeOff"; +const VehicleProperty::Property VehicleProperty::YawRate = "YawRate"; +const VehicleProperty::Property VehicleProperty::ButtonEventW3C = "ButtonEventW3C"; PropertyList VehicleProperty::mCapabilities; PropertyList VehicleProperty::mCustomProperties; @@ -200,41 +228,43 @@ VehicleProperty::VehicleProperty() { REGISTERPROPERTY( VehicleSpeed, 0); REGISTERPROPERTY(EngineSpeed, 0); - REGISTERPROPERTY(TransmissionShiftPosition,Transmission::Neutral); - REGISTERPROPERTY(TransmissionGearPosition,Transmission::Neutral); - REGISTERPROPERTY(TransmissionMode,Transmission::Normal); - REGISTERPROPERTY(TransmissionModeW3C,"neutral"); + REGISTERPROPERTY(TransmissionShiftPosition, Transmission::Neutral); + REGISTERPROPERTY(TransmissionGearPosition, Transmission::Neutral); + REGISTERPROPERTY(TransmissionMode, Transmission::Normal); + REGISTERPROPERTY(TransmissionModeW3C, "neutral"); REGISTERPROPERTY(ThrottlePosition, 0); REGISTERPROPERTY(WheelBrake, false); - REGISTERPROPERTY(WheelBrakePressure,0); - REGISTERPROPERTY(SteeringWheelAngle,0); - REGISTERPROPERTY(SteeringWheelAngleW3C,0); + REGISTERPROPERTY(WheelBrakePressure, 0); + REGISTERPROPERTY(SteeringWheelAngle, 0); + REGISTERPROPERTY(SteeringWheelAngleW3C, 0); REGISTERPROPERTY(TurnSignal, TurnSignals::Off); REGISTERPROPERTY(ClutchStatus, false); REGISTERPROPERTY(EngineOilPressure, 0); REGISTERPROPERTY(EngineOilTemperature, 0); - REGISTERPROPERTY(EngineOilRemaining,0); + REGISTERPROPERTY(EngineOilRemaining, 0); + REGISTERPROPERTY(EngineOilLifeRemaining, 0); + REGISTERPROPERTY(EngineOilChangeIndicator, false); REGISTERPROPERTY(EngineCoolantTemperature, 0); REGISTERPROPERTY(EngineCoolantLevel, 0); REGISTERPROPERTY(MachineGunTurretStatus, false); - REGISTERPROPERTY(AccelerationX,0); - REGISTERPROPERTY(AccelerationY,0); - REGISTERPROPERTY(AccelerationZ,0); - REGISTERPROPERTY(MassAirFlow,0); + REGISTERPROPERTY(AccelerationX, 0); + REGISTERPROPERTY(AccelerationY, 0); + REGISTERPROPERTY(AccelerationZ, 0); + REGISTERPROPERTY(MassAirFlow, 0); REGISTERPROPERTY(ButtonEvent, ButtonEvents::NoButton); - REGISTERPROPERTY(AirIntakeTemperature,0) + REGISTERPROPERTY(AirIntakeTemperature, 0) REGISTERPROPERTY(BatteryVoltage, 0); - REGISTERPROPERTY(BatteryCurrent,0); - REGISTERPROPERTY(BatteryChargeLevel,0); + REGISTERPROPERTY(BatteryCurrent, 0); + REGISTERPROPERTY(BatteryChargeLevel, 0); REGISTERPROPERTY(InteriorTemperature, 0); - REGISTERPROPERTY(ExteriorTemperature,0); + REGISTERPROPERTY(ExteriorTemperature, 0); REGISTERPROPERTY(VIN, ""); REGISTERPROPERTY(WMI, ""); REGISTERPROPERTY(TirePressure, 0); REGISTERPROPERTY(TirePressureLow, false); - REGISTERPROPERTY(TireTemperature,0); - REGISTERPROPERTY( VehiclePowerMode,Power::Off); - registerPropertyPriv(TripMeters,[](){ + REGISTERPROPERTY(TireTemperature, 0); + REGISTERPROPERTY( VehiclePowerMode, Power::Off); + registerPropertyPriv(TripMeters, [](){ TripMetersType* t = new TripMetersType(); BasicPropertyType<uint16_t> v(0); t->append(&v); @@ -242,7 +272,7 @@ VehicleProperty::VehicleProperty() }); REGISTERPROPERTY(CruiseControlActive, false); - REGISTERPROPERTY(CruiseControlSpeed,0); + REGISTERPROPERTY(CruiseControlSpeed, 0); REGISTERPROPERTY(LightHead, false); REGISTERPROPERTY(LightLeftTurn, false); REGISTERPROPERTY(LightRightTurn, false); @@ -256,6 +286,7 @@ VehicleProperty::VehicleProperty() REGISTERPROPERTY(InteriorLightDriver, false); REGISTERPROPERTY(InteriorLightPassenger, false); REGISTERPROPERTY(InteriorLightCenter, false); + REGISTERPROPERTY(InteriorLightStatus, false); REGISTERPROPERTY(EngineLoad, 0); REGISTERPROPERTY(Horn, false); REGISTERPROPERTY(FuelLevel, 0); @@ -274,7 +305,7 @@ VehicleProperty::VehicleProperty() REGISTERPROPERTY(VehicleLength, 0); REGISTERPROPERTY(Latitude, 0); REGISTERPROPERTY(Longitude, 0); - REGISTERPROPERTY(Altitude,0); + REGISTERPROPERTY(Altitude, 0); REGISTERPROPERTY(Direction, 0); REGISTERPROPERTY(VehicleType, Vehicle::Unknown); registerPropertyPriv(DoorsPerRow, []() { BasicPropertyType<uint16_t> d(0); return new DoorsPerRowType(&d); }); @@ -286,10 +317,10 @@ VehicleProperty::VehicleProperty() REGISTERPROPERTY(Odometer, 0); REGISTERPROPERTY(DistanceTotal, 0); REGISTERPROPERTY(DistanceSinceStart, 0); - REGISTERPROPERTY(TransmissionFluidLevel,0); - REGISTERPROPERTY(BrakeFluidLevel,0); - REGISTERPROPERTY(WasherFluidLevel,0); - REGISTERPROPERTY(SecurityAlertStatus,Security::Idle); + REGISTERPROPERTY(TransmissionFluidLevel, 0); + REGISTERPROPERTY(BrakeFluidLevel, 0); + REGISTERPROPERTY(WasherFluidLevel, 0); + REGISTERPROPERTY(SecurityAlertStatus, Security::Idle); REGISTERPROPERTY(ParkingBrakeStatus, false); REGISTERPROPERTY(ParkingLightStatus, false); REGISTERPROPERTY(HazardLightStatus, false); @@ -318,11 +349,11 @@ VehicleProperty::VehicleProperty() REGISTERPROPERTY(AirRecirculation, false); REGISTERPROPERTY(Heater, false); - REGISTERPROPERTY(Defrost,false); - REGISTERPROPERTY(DefrostWindow,false); - REGISTERPROPERTY(DefrostMirror,false); + REGISTERPROPERTY(Defrost, false); + REGISTERPROPERTY(DefrostWindow, false); + REGISTERPROPERTY(DefrostMirror, false); - REGISTERPROPERTY(SteeringWheelHeater,false); + REGISTERPROPERTY(SteeringWheelHeater, false); REGISTERPROPERTY(SeatHeater, 0); REGISTERPROPERTY(SeatCooler, false); REGISTERPROPERTY(WindowStatus, 100); @@ -332,40 +363,36 @@ VehicleProperty::VehicleProperty() REGISTERPROPERTY(NightMode, false); REGISTERPROPERTY(DrivingMode, Driving::None); REGISTERPROPERTY(DrivingModeW3C, false); - REGISTERPROPERTY(KeyId,""); - REGISTERPROPERTY(Language,""); - REGISTERPROPERTY(MeasurementSystem,Measurement::Metric); - REGISTERPROPERTY(MirrorSettingPan,0); - REGISTERPROPERTY(MirrorSettingTilt,0); - REGISTERPROPERTY(SteeringWheelPositionSlide,0); - REGISTERPROPERTY(SteeringWheelPositionTilt,0); - REGISTERPROPERTY(SeatPositionRecline,0); - REGISTERPROPERTY(SeatPositionSlide,0); - REGISTERPROPERTY(SeatPositionCushionHeight,0); - REGISTERPROPERTY(SeatPositionHeadrest,0); - REGISTERPROPERTY(SeatPositionBackCushion,0); - REGISTERPROPERTY(SeatPositionSideCushion,0); - REGISTERPROPERTY(DashboardIllumination,0); + REGISTERPROPERTY(KeyId, ""); + REGISTERPROPERTY(Language, ""); + REGISTERPROPERTY(MeasurementSystem, Measurement::Metric); + REGISTERPROPERTY(MirrorSettingPan, 0); + REGISTERPROPERTY(MirrorSettingTilt, 0); + REGISTERPROPERTY(SteeringWheelPositionSlide, 0); + REGISTERPROPERTY(SteeringWheelPositionTilt, 0); + REGISTERPROPERTY(SeatPositionRecline, 0); + REGISTERPROPERTY(SeatPositionSlide, 0); + REGISTERPROPERTY(SeatPositionCushionHeight, 0); + REGISTERPROPERTY(SeatPositionHeadrest, 0); + REGISTERPROPERTY(SeatPositionBackCushion, 0); + REGISTERPROPERTY(SeatPositionSideCushion, 0); + REGISTERPROPERTY(DashboardIllumination, 0); REGISTERPROPERTY(GeneratedVehicleSoundMode, Vehicle::Normal); REGISTERPROPERTY(DriverId, ""); - + REGISTERPROPERTY(PowertrainTorque, 0); + REGISTERPROPERTY(AcceleratorPedalPosition, 0); + REGISTERPROPERTY(Chime, false); + REGISTERPROPERTY(WheelTick, 0); + REGISTERPROPERTY(IgnitionTimeOff, 0); + REGISTERPROPERTY(IgnitionTimeOn, 0); + REGISTERPROPERTY(YawRate, 0); + REGISTERPROPERTY(ButtonEventW3C, ""); } void VehicleProperty::factory() { if(!thereCanOnlyBeOne) - thereCanOnlyBeOne = new VehicleProperty(); -} - -void VehicleProperty::shutdown() -{ - if(thereCanOnlyBeOne){ - delete thereCanOnlyBeOne; - thereCanOnlyBeOne = nullptr; - } - registeredPropertyFactoryMap.clear(); - mCapabilities.clear(); - mCustomProperties.clear(); + thereCanOnlyBeOne = amb::make_unique(new VehicleProperty()); } PropertyList VehicleProperty::capabilities() diff --git a/lib/vehicleproperty.h b/lib/vehicleproperty.h index 3c5b97d5..a79e4ce1 100644 --- a/lib/vehicleproperty.h +++ b/lib/vehicleproperty.h @@ -48,6 +48,25 @@ enum ButtonEventType { NavigateLeftButton = 1 << 11, NavigateRightButton = 1 << 12 }; + +namespace W3C +{ +extern const char* Home; +extern const char* Back; +extern const char* Search; +extern const char* Call; +extern const char* EndCall; +extern const char* MediaPlay; +extern const char* MediaNext; +extern const char* MediaPrevious; +extern const char* MediaPause; +extern const char* VoiceRecognize; +extern const char* Enter; +extern const char* Left; +extern const char* Right; +extern const char* Up; +extern const char* Down; +} } namespace TurnSignals { @@ -334,12 +353,6 @@ public: */ static void factory(); - /*! - * - * \brief destroys static instance of VehicleProperty. This should be called at application shutdown - */ - static void shutdown(); - typedef std::string Property; /*! @@ -439,7 +452,7 @@ public: /**< Engine coolant temperature in degrees celcius **/ static const Property EngineCoolantTemperature; - PROPERTYTYPE(EngineCoolantTemperature, EngineCoolantTemperatureType, BasicPropertyType<int>, int) + PROPERTYTYPEBASIC(EngineCoolantTemperature, int16_t) static const Property EngineCoolantLevel; PROPERTYTYPE(EngineCoolantLevel, EngineCoolantLevelType, BasicPropertyType<uint>, uint) @@ -448,17 +461,14 @@ public: static const Property MachineGunTurretStatus; PROPERTYTYPEBASIC(MachineGunTurretStatus, bool) - /**< Acceleration on the 'x' axis in 1/1000 gravitational acceleration "g-force" */ static const Property AccelerationX; - PROPERTYTYPE(AccelerationX, AccelerationXType, BasicPropertyType<uint16_t>, uint16_t) + PROPERTYTYPEBASIC(AccelerationX, int16_t) - /**< Acceleration on the 'y' axis in 1/1000 gravitational acceleration "g-force" */ static const Property AccelerationY; - PROPERTYTYPE(AccelerationY, AccelerationYType, BasicPropertyType<uint16_t>, uint16_t) + PROPERTYTYPEBASIC(AccelerationY, int16_t) - /**< Acceleration on the 'z' axis in 1/1000 gravitational acceleration "g-force" */ static const Property AccelerationZ; - PROPERTYTYPE(AccelerationZ, AccelerationZType, BasicPropertyType<uint16_t>, uint16_t) + PROPERTYTYPEBASIC(AccelerationZ, int16_t) /**< Mass Air Flow. grams/sec */ static const Property MassAirFlow; @@ -466,9 +476,12 @@ public: //typedef BasicPropertyType<uint16_t> MassAirFlowType; /**< Button Event @see ButtonEvents::ButtonEventType */ + ///TODO: deprecated. Use ButtonEventW3C. Remove in 0.14 static const Property ButtonEvent; PROPERTYTYPE(ButtonEvent, ButtonEventType, BasicPropertyType<ButtonEvents::ButtonEventType>, ButtonEvents::ButtonEventType) - //typedef BasicPropertyType<ButtonEvents::ButtonEventType> ButtonEventType; + + static const Property ButtonEventW3C; + PROPERTYTYPE(ButtonEventW3C, ButtonEventW3CType, StringPropertyType, std::string) /**< Air intake temperature in degrees celcius */ static const Property AirIntakeTemperature; @@ -496,14 +509,17 @@ public: PROPERTYTYPE(ExteriorTemperature, ExteriorTemperatureType, BasicPropertyType<int>, int) //typedef BasicPropertyType<int> ExteriorTemperatureType; - /**< Engine Oil Temperature in degrees celcius */ static const Property EngineOilTemperature; - PROPERTYTYPE(EngineOilTemperature, EngineOilTemperatureType, BasicPropertyType<int>, int) - //typedef BasicPropertyType<int> EngineOilTemperatureType; + PROPERTYTYPEBASIC(EngineOilTemperature, int) static const Property EngineOilRemaining; - PROPERTYTYPE(EngineOilRemaining, EngineOilRemainingType,BasicPropertyType<uint16_t>, uint16_t) - //typedef BasicPropertyType<uint16_t> EngineOilRemainingType; + PROPERTYTYPEBASIC(EngineOilRemaining, uint16_t) + + static const Property EngineOilLifeRemaining; + PROPERTYTYPEBASIC(EngineOilLifeRemaining, uint8_t) + + static const Property EngineOilChangeIndicator; + PROPERTYTYPEBASIC(EngineOilChangeIndicator, bool) /**< Vehicle Identification Number (ISO 3779) 17 chars**/ static const Property VIN; @@ -567,14 +583,19 @@ public: static const Property LightDynamicHighBeam; PROPERTYTYPEBASIC(LightDynamicHighBeam, bool) - + ///TODO: deprecated. Use InteriorLightStatus which is zoned. Remove in 0.14 static const Property InteriorLightDriver; PROPERTYTYPE(InteriorLightDriver, InteriorLightDriverType, BasicPropertyType<bool>, bool) + ///TODO: deprecated. Use InteriorLightStatus which is zoned. Remove in 0.14 static const Property InteriorLightCenter; PROPERTYTYPE(InteriorLightCenter, InteriorLightCenterType, BasicPropertyType<bool>, bool) + ///TODO: deprecated. Use InteriorLightStatus which is zoned. Remove in 0.14 static const Property InteriorLightPassenger; PROPERTYTYPE(InteriorLightPassenger, InteriorLightPassengerType, BasicPropertyType<bool>, bool) + static const Property InteriorLightStatus; + PROPERTYTYPEBASIC(InteriorLightStatus, bool) + static const Property EngineLoad; PROPERTYTYPE(EngineLoad, EngineLoadType, BasicPropertyType<uint16_t>, uint16_t) @@ -879,6 +900,26 @@ public: static const Property DriverId; PROPERTYTYPE(DriverId, DriverIdType, StringPropertyType, std::string) + static const Property PowertrainTorque; + PROPERTYTYPEBASIC(PowertrainTorque, uint16_t) + + static const Property AcceleratorPedalPosition; + PROPERTYTYPEBASIC(AcceleratorPedalPosition, uint8_t) + + static const Property Chime; + PROPERTYTYPEBASIC(Chime, bool) + + static const Property WheelTick; + PROPERTYTYPEBASIC(WheelTick, uint) + + static const Property IgnitionTimeOn; + PROPERTYTYPEBASIC(IgnitionTimeOn, uint64_t) + + static const Property IgnitionTimeOff; + PROPERTYTYPEBASIC(IgnitionTimeOff, uint64_t) + + static const Property YawRate; + PROPERTYTYPEBASIC(YawRate, int16_t) /** END PROPERTIES **/ @@ -928,7 +969,7 @@ private: VehicleProperty(); - static VehicleProperty* thereCanOnlyBeOne; + static std::unique_ptr<VehicleProperty> thereCanOnlyBeOne; static bool registerPropertyPriv(Property name, PropertyTypeFactoryCallback factory); diff --git a/plugins/bluemonkey/bluemonkey.cpp b/plugins/bluemonkey/bluemonkey.cpp index a7f0785c..f2fb0489 100644 --- a/plugins/bluemonkey/bluemonkey.cpp +++ b/plugins/bluemonkey/bluemonkey.cpp @@ -181,7 +181,7 @@ void BluemonkeySink::loadConfig(QString str) QFile file(str); if(!file.open(QIODevice::ReadOnly)) { - DebugOut()<<"failed to open config file: "<<str.toStdString()<<endl; + DebugOut(DebugOut::Error)<<"failed to open config file: "<<str.toStdString()<<endl; return; } @@ -322,7 +322,7 @@ void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTi routingEngine->getRangePropertyAsync(request); } -void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, Zone::Type zone = Zone::None) +void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, int zone = Zone::None) { auto create = [defaultValue, name]() -> AbstractPropertyType* diff --git a/plugins/bluemonkey/bluemonkey.h b/plugins/bluemonkey/bluemonkey.h index 13ee9bae..2a08856e 100644 --- a/plugins/bluemonkey/bluemonkey.h +++ b/plugins/bluemonkey/bluemonkey.h @@ -88,7 +88,11 @@ private: class BluemonkeySink : public QObject, public AmbPluginImpl { Q_OBJECT + public: + using AmbPluginImpl::setProperty; + using QObject::setProperty; + BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource& parent); virtual PropertyList subscriptions(); virtual void supportedChanged(const PropertyList & supportedProperties); @@ -137,7 +141,7 @@ public Q_SLOTS: mSilentMode = m; } - void createCustomProperty(QString name, QJSValue defaultValue, Zone::Type zone); + void createCustomProperty(QString name, QJSValue defaultValue, int zone); private: QStringList configsToLoad; diff --git a/plugins/cangenplugin/cangenplugin.cpp b/plugins/cangenplugin/cangenplugin.cpp index 5ed91b97..c5ccdd6d 100644 --- a/plugins/cangenplugin/cangenplugin.cpp +++ b/plugins/cangenplugin/cangenplugin.cpp @@ -88,7 +88,7 @@ AsyncPropertyReply *CANGenPlugin::setProperty(const AsyncSetPropertyRequest &req { std::string v = request.value->toString(); - dataReceived(nullptr,v.c_str(),v.length()); + dataReceived(nullptr, v.c_str(), v.length()); } return AmbPluginImpl::setProperty(request); @@ -408,13 +408,13 @@ void CANGenPlugin::dataReceived(libwebsocket* socket, const char* data, size_t l } else if (name == "set") { + LOG_MESSAGE("set called"); if (!propertyNames.empty()) { //Should not happen } else if (!propertyData.empty()) { - auto prop = propertyData.begin(); for (auto prop = propertyData.begin(); prop != propertyData.end(); ++prop) { LOG_MESSAGE("websocketsinkmanager setting " << std::get<1>(*prop) << " to " << std::get<2>(*prop) << " in zone " << std::get<3>(*prop)); diff --git a/plugins/common/ambplugin.h b/plugins/common/ambplugin.h index 47191280..47fc94e4 100644 --- a/plugins/common/ambplugin.h +++ b/plugins/common/ambplugin.h @@ -207,7 +207,9 @@ void AmbPlugin<T>::getRangePropertyAsync(AsyncRangePropertyReply *reply) template<typename T> AsyncPropertyReply* AmbPlugin<T>::setProperty(AsyncSetPropertyRequest request) { - return d ? d->AmbPluginImpl::setProperty(request) : nullptr; + if(d) + return d->setProperty(request); + return nullptr; } template<typename T> diff --git a/plugins/database/databasesink.cpp b/plugins/database/databasesink.cpp index dbc141e4..ae18d36a 100644 --- a/plugins/database/databasesink.cpp +++ b/plugins/database/databasesink.cpp @@ -122,7 +122,6 @@ int getNextEvent(gpointer data) pbshared->playbackQueue.remove(obj); DebugOut()<<"playback Queue size: "<<pbshared->playbackQueue.size()<<endl; - //delete obj; return 0; } @@ -329,16 +328,14 @@ void DatabaseSink::startPlayback() obj.key = results[i][0]; obj.value = results[i][1]; obj.source = results[i][2]; - obj.time = boost::lexical_cast<double>(results[i][3]); - - /// TODO: figure out why sequence is broken: - -// obj->sequence = boost::lexical_cast<int>(results[i][4]); + obj.zone = boost::lexical_cast<double>(results[i][3]); + obj.time = boost::lexical_cast<double>(results[i][4]); + obj.sequence = boost::lexical_cast<double>(results[i][5]); playbackShared->playbackQueue.push_back(obj); } - g_timeout_add(0,getNextEvent,playbackShared); + g_timeout_add(0, getNextEvent, playbackShared); } void DatabaseSink::initDb() diff --git a/plugins/database/databasesink.h b/plugins/database/databasesink.h index 2ec319f1..bb9697ae 100644 --- a/plugins/database/databasesink.h +++ b/plugins/database/databasesink.h @@ -172,7 +172,8 @@ public: bool operator ==(const DBObject & other) const { - return (key == other.key && source == other.source && zone == other.zone); + return (key == other.key && source == other.source && zone == other.zone && + value == other.value && sequence == other.sequence && time == other.time); } bool operator != (const DBObject & other) diff --git a/plugins/dbus/automotivemanager.cpp b/plugins/dbus/automotivemanager.cpp index 7955ac89..da49d9c2 100644 --- a/plugins/dbus/automotivemanager.cpp +++ b/plugins/dbus/automotivemanager.cpp @@ -124,7 +124,7 @@ static void handleMethodCall(GDBusConnection *connection, if(propertyToFind == "") { - g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument."); + g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument."); return; } @@ -132,7 +132,7 @@ static void handleMethodCall(GDBusConnection *connection, if(!interfaces.size()) { - g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found"); + g_dbus_method_invocation_return_dbus_error(invocation, "org.automotive.Manager.ObjectNotFound", "Property not found"); return; } @@ -160,7 +160,7 @@ static void handleMethodCall(GDBusConnection *connection, } } - g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found"); + g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.InvalidZone", "zone not found"); } else if (method == "ZonesForObjectName") @@ -198,7 +198,7 @@ static void handleMethodCall(GDBusConnection *connection, g_dbus_method_invocation_return_value(invocation,g_variant_new("(ai)",¶ms)); } - + else if(method == "List") { std::list<AbstractDBusInterface*> list = AbstractDBusInterface::interfaces(); diff --git a/plugins/dbus/dbusinterfacemanager.cpp b/plugins/dbus/dbusinterfacemanager.cpp index 3ca7f279..4200784b 100644 --- a/plugins/dbus/dbusinterfacemanager.cpp +++ b/plugins/dbus/dbusinterfacemanager.cpp @@ -218,6 +218,12 @@ on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_d exportProperty<EngineCoolant>(iface->re, connection); exportProperty<NightMode>(iface->re, connection); exportProperty<DrivingMode>(iface->re, connection); + exportProperty<PowertrainTorque>(iface->re, connection); + exportProperty<AcceleratorPedalPosition>(iface->re, connection); + exportProperty<Chime>(iface->re, connection); + exportProperty<WheelTick>(iface->re, connection); + exportProperty<IgnitionTime>(iface->re, connection); + exportProperty<YawRate>(iface->re, connection); iface->registerCustomTypes(); } diff --git a/plugins/dbus/environmentproperties.h b/plugins/dbus/environmentproperties.h index 10db753c..3815152d 100644 --- a/plugins/dbus/environmentproperties.h +++ b/plugins/dbus/environmentproperties.h @@ -28,7 +28,7 @@ class Temperature: public DBusSink { public: Temperature(AbstractRoutingEngine* re, GDBusConnection* connection) - :DBusSink("InteriorTemperature", re, connection, map<string, string>()) + :DBusSink("Temperature", re, connection, map<string, string>()) { /** * @attributeName Interior diff --git a/plugins/dbus/runningstatus.h b/plugins/dbus/runningstatus.h index 38f0b873..d66d4c64 100644 --- a/plugins/dbus/runningstatus.h +++ b/plugins/dbus/runningstatus.h @@ -116,26 +116,9 @@ public: AccelerationProperty(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("Acceleration", re, connection, map<string, string>()) { - /** @attributeName X - * @type unsigned short - * @access readonly - * @attributeComment \brief Must return acceleration on the "X" axis as 1/1000 G (gravitational force). - **/ - wantPropertyVariant(VehicleProperty::AccelerationX, "X", "q", AbstractProperty::Read); - - /** @attributeName Y - * @type unsigned short - * @access readonly - * @attributeComment \brief Must return acceleration on the "Y" axis as 1/1000 G (gravitational force). - **/ - wantPropertyVariant(VehicleProperty::AccelerationY, "Y", "q", AbstractProperty::Read); - - /** @attributeName Z - * @type unsigned short - * @access readonly - * @attributeComment \brief Must return acceleration on the "Z" axis as 1/1000 G (gravitational force). - **/ - wantPropertyVariant(VehicleProperty::AccelerationZ, "Z", "q", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::AccelerationX, "X", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::AccelerationY, "Y", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::AccelerationZ, "Z", AbstractProperty::Read); } }; @@ -171,25 +154,15 @@ public: CruiseControlProperty(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("CruiseControlStatus", re, connection, map<string, string>()) { - /** @attributeName Activated - * @type boolean - * @access readonly - * @attributeComment \brief Must return whether or not the Cruise Control system is active (true) or inactive (false) - **/ - wantPropertyVariant(VehicleProperty::CruiseControlActive, "Activated", "b", AbstractProperty::Read); - - /** @attributeName Speed - * @type unsigned short - * @access readonly - * @attributeComment \brief Must return target Cruise Control speed in kilometers per hour (kph). - **/ - wantPropertyVariant(VehicleProperty::CruiseControlSpeed, "Speed", "q", AbstractProperty::Read); - + ///TODO: deprecate Activated. Remove in 0.14 + wantPropertyVariant(VehicleProperty::CruiseControlActive, "Activated", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::CruiseControlSpeed, "Speed", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::CruiseControlActive, "Status", AbstractProperty::Read); } }; /** @interface WheelBrake : VehiclePropertyType **/ -/// TODO: deprecated remove in 0.13 +/// TODO: deprecated remove in 0.14 class WheelBrakeProperty: public DBusSink { public: @@ -218,7 +191,7 @@ public: * @access readonly * @attributeComment \brief Must return Wheel Brake status: Engaged = true, disengaged = false **/ - wantPropertyVariant(VehicleProperty::WheelBrake, "brakePedalDepressed", "b", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::WheelBrake, "BrakePedalDepressed", AbstractProperty::Read); } }; @@ -230,96 +203,34 @@ public: LightStatusProperty(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("LightStatus", re, connection, map<string, string>()) { - /** @attributeName Head - * @type boolean - * @access readonly - * @attributeComment \brief Must return headlight status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightHead, "Head", "b", AbstractProperty::Read); - - /** @attributeName RightTurn - * @type boolean - * @access readonly - * @attributeComment \brief Must return right turn signal status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightRightTurn, "RightTurn", "b", AbstractProperty::Read); - - /** @attributeName LeftTurn - * @type boolean - * @access readonly - * @attributeComment \brief Must return left turn signal status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightLeftTurn, "LeftTurn", "b", AbstractProperty::Read); - - /** @attributeName Brake - * @type boolean - * @access readonly - * @attributeComment \brief Must return brake signal light status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightBrake, "Brake", "b", AbstractProperty::Read); - - /** @attributeName Fog - * @type boolean - * @access readonly - * @attributeComment \brief Must return fog light status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightFog, "Fog", "b", AbstractProperty::Read); - - /** @attributeName Hazard - * @type boolean - * @access readonly - * @attributeComment \brief Must return hazard light status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightHazard, "Hazard", "b", AbstractProperty::Read); - - /** @attributeName Parking - * @type boolean - * @access readonly - * @attributeComment \brief Must return parking light status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightParking, "Parking", "b", AbstractProperty::Read); - - /** @attributeName HighBeam - * @type boolean - * @access readonly - * @attributeComment \brief Must return high beam status: on = true, off = false. - **/ - wantPropertyVariant(VehicleProperty::LightHighBeam, "HighBeam", "b", AbstractProperty::Read); - - wantPropertyVariant(VehicleProperty::LightAutomatic, "automaticHeadlights", AbstractProperty::Read); - wantPropertyVariant(VehicleProperty::LightDynamicHighBeam, "dynamicHighBeam", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::LightHead, "Head", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightRightTurn, "RightTurn", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightLeftTurn, "LeftTurn", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightBrake, "Brake", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightFog, "Fog", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightHazard, "Hazard", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightParking, "Parking", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightHighBeam, "HighBeam", "b", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightAutomatic, "AutomaticHeadlights", AbstractProperty::ReadWrite); + wantPropertyVariant(VehicleProperty::LightDynamicHighBeam, "DynamicHighBeam", AbstractProperty::ReadWrite); } }; -/** @interface InteriorLightStatus : VehiclePropertyType **/ class InteriorLightStatusProperty: public DBusSink { public: InteriorLightStatusProperty(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("InteriorLightStatus", re, connection, map<string, string>()) { - /** @attributeName Passenger - * @type boolean - * @access readonly - * @attributeComment \brief Must return passenger interior light status: on = true, off = false - **/ - wantPropertyVariant(VehicleProperty::InteriorLightPassenger, "Passenger", "b", AbstractProperty::Read); - - /** @attributeName Driver - * @type boolean - * @access readonly - * @attributeComment \brief Must return driver interior light status: on = true, off = false - **/ - wantPropertyVariant(VehicleProperty::InteriorLightPassenger, "Driver", "b", AbstractProperty::Read); - - /** @attributeName Center - * @type boolean - * @access readonly - * @attributeComment \brief Must return center interior light status: on = true, off = false - **/ - wantPropertyVariant(VehicleProperty::InteriorLightCenter, "Center", "b", AbstractProperty::Read); - + /// TODO: deprecated remove in 0.14 + wantPropertyVariant(VehicleProperty::InteriorLightPassenger, "Passenger", AbstractProperty::Read); + /// TODO: deprecated remove in 0.14 + wantPropertyVariant(VehicleProperty::InteriorLightPassenger, "Driver", AbstractProperty::Read); + /// TODO: deprecated remove in 0.14 + wantPropertyVariant(VehicleProperty::InteriorLightCenter, "Center", AbstractProperty::Read); + + wantPropertyVariant(VehicleProperty::InteriorLightStatus, "Status", AbstractProperty::ReadWrite); } }; @@ -330,12 +241,9 @@ public: HornProperty(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("Horn", re, connection, map<string, string>()) { - /** @attributeName On - * @type boolean - * @access readonly - * @attributeComment \brief Must return horn status: on = true, off = false - **/ - wantPropertyVariant(VehicleProperty::Horn,"On","b",AbstractProperty::Read); + /// TODO: deprecated remove in 0.14 + wantPropertyVariant(VehicleProperty::Horn,"On",AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::Horn,"Status",AbstractProperty::Read); } }; @@ -373,26 +281,13 @@ public: EngineOilProperty(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("EngineOil", re, connection, map<string, string>()) { - /** @attributeName Remaining - * @type unsigned short - * @access readonly - * @attributeComment \brief Must return remaining engine oil as percentage of fullness. - **/ - wantPropertyVariant(VehicleProperty::EngineOilRemaining, "Remaining", "q", AbstractProperty::Read); - - /** @attributeName Temperature - * @type long - * @access readonly - * @attributeComment \brief Must return Engine Oil Temperature in Celcius. - **/ - wantPropertyVariant(VehicleProperty::EngineOilTemperature, "Temperature", "i", AbstractProperty::Read); - - /** @attributeName Pressure - * @type unsigned short - * @access readonly - * @attributeComment \brief Must return Engine Oil Pressure in kPa. - **/ - wantPropertyVariant(VehicleProperty::EngineOilPressure, "Pressure", "q", AbstractProperty::Read); + ///TODO depricated. Use Level. Remove in 0.14 + wantPropertyVariant(VehicleProperty::EngineOilRemaining, "Remaining", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::EngineOilRemaining, "Level", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::EngineOilTemperature, "Temperature", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::EngineOilPressure, "Pressure", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::EngineOilChangeIndicator, "Change", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::EngineOilLifeRemaining, "LifeRemaining", AbstractProperty::Read); } }; @@ -451,7 +346,7 @@ public: ThrottlePosition(AbstractRoutingEngine *re, GDBusConnection *connection) :DBusSink("ThrottlePosition", re, connection, map<string, string>()) { - wantPropertyVariant(VehicleProperty::ThrottlePosition, "Value", "i", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::ThrottlePosition, "Value", AbstractProperty::Read); } }; @@ -477,4 +372,65 @@ public: } }; +class PowertrainTorque: public DBusSink +{ +public: + PowertrainTorque(AbstractRoutingEngine *re, GDBusConnection *connection) + :DBusSink("PowertrainTorque", re, connection, map<string, string>()) + { + wantPropertyVariant(VehicleProperty::PowertrainTorque, "Value", AbstractProperty::Read); + } +}; + +class AcceleratorPedalPosition: public DBusSink +{ +public: + AcceleratorPedalPosition(AbstractRoutingEngine *re, GDBusConnection *connection) + :DBusSink("AcceleratorPedalPosition", re, connection, map<string, string>()) + { + wantPropertyVariant(VehicleProperty::AcceleratorPedalPosition, "Value", AbstractProperty::Read); + } +}; + +class Chime: public DBusSink +{ +public: + Chime(AbstractRoutingEngine *re, GDBusConnection *connection) + :DBusSink("Chime", re, connection, map<string, string>()) + { + wantPropertyVariant(VehicleProperty::Chime, "Status", AbstractProperty::Read); + } +}; + +class WheelTick: public DBusSink +{ +public: + WheelTick(AbstractRoutingEngine *re, GDBusConnection *connection) + :DBusSink("WheelTick", re, connection, map<string, string>()) + { + wantPropertyVariant(VehicleProperty::WheelTick, "Value", AbstractProperty::Read); + } +}; + +class IgnitionTime: public DBusSink +{ +public: + IgnitionTime(AbstractRoutingEngine *re, GDBusConnection *connection) + :DBusSink("IgnitionTime", re, connection, map<string, string>()) + { + wantPropertyVariant(VehicleProperty::IgnitionTimeOn, "IgnitionTimeOn", AbstractProperty::Read); + wantPropertyVariant(VehicleProperty::IgnitionTimeOff, "IgnitionTimeOff", AbstractProperty::Read); + } +}; + +class YawRate: public DBusSink +{ +public: + YawRate(AbstractRoutingEngine *re, GDBusConnection *connection) + :DBusSink("YawRate", re, connection, map<string, string>()) + { + wantPropertyVariant(VehicleProperty::YawRate, "Value", AbstractProperty::Read); + } +}; + #endif diff --git a/plugins/obd2plugin/obd2source.cpp b/plugins/obd2plugin/obd2source.cpp index c95bda20..1be11126 100644 --- a/plugins/obd2plugin/obd2source.cpp +++ b/plugins/obd2plugin/obd2source.cpp @@ -277,7 +277,7 @@ void threadLoop(gpointer data) connected = false; StatusMessage *statusreq = new StatusMessage(); statusreq->statusStr = "disconnected"; - g_async_queue_push(privStatusQueue,statusreq); + g_async_queue_push(privStatusQueue, statusreq); } delete req; } @@ -468,7 +468,7 @@ static int updateProperties( gpointer data) } else if (reply->statusStr == "connected") { - src->obd2Connected.setValue(false); + src->obd2Connected.setValue(true); src->updateProperty(&src->obd2Connected); } else if (reply->statusStr == "error:nodata" || reply->statusStr == "error:timeout") @@ -519,11 +519,10 @@ static int updateProperties( gpointer data) void OBD2Source::updateProperty(AbstractPropertyType* value) { VehicleProperty::Property property = value->name; - if(property == Obd2Connected) - obd2Connected.setValue(value->anyValue()); - AsyncPropertyReply* reply = nullptr; + DebugOut() << "updateProperty for: " << property << "value: " << value->toString() << endl; + for(auto i : propertyReplyList) { if(i->property == property) @@ -547,24 +546,28 @@ void OBD2Source::updateProperty(AbstractPropertyType* value) removeOne(&propertyReplyList, reply); } - else - { - if(oldValueMap.find(property) != oldValueMap.end()) - { - AbstractPropertyType* old = oldValueMap[property]; - if((*old) == (*value)) - { - return; - } + if(oldValueMap.find(property) != oldValueMap.end()) + { + AbstractPropertyType* old = oldValueMap[property]; - delete old; + if((*old) == (*value)) + { + DebugOut() << "old value is same as new for: " << value->name << endl; + return; } + delete old; + oldValueMap.erase(property); + } + else + { oldValueMap[property] = value->copy(); - - m_re->updateProperty(value, uuid()); } + + DebugOut() << "updateProperty for: " << property << "value: " << value->toString() << endl; + m_re->updateProperty(value, uuid()); + } void OBD2Source::setSupported(PropertyList list) @@ -616,22 +619,6 @@ void OBD2Source::setConfiguration(map<string, string> config) m_btDeviceAddress = port; m_btAdapterAddress = btadapter; m_isBluetooth = true; - ///TODO: bluetooth!! - /*DebugOut()<<"bluetooth device?"<<endl; - BluetoothDevice bt; - - std::string tempPort = bt.getDeviceForAddress(port, btadapter); - if(tempPort != "") - { - DebugOut(3)<<"Using bluetooth device \""<<port<<"\" bound to: "<<tempPort<<endl; - port = tempPort; - } - else - { - DebugOut(0)<<"Device Error"<<endl; - ///Don't throw here. - //throw std::runtime_error("Device Error"); - }*/ } //connect(obd, port, baud); @@ -639,19 +626,18 @@ void OBD2Source::setConfiguration(map<string, string> config) req->req = "setportandbaud"; req->arglist.push_back(port); req->arglist.push_back(baud); - g_async_queue_push(commandQueue,req); + g_async_queue_push(commandQueue, req); m_port = port; m_baud = baud; - m_gThread = g_thread_new("mythread",(GThreadFunc)&threadLoop,this); - //g_idle_add(updateProperties, this); - g_timeout_add(5,updateProperties,this); + m_gThread = g_thread_new("mythread", (GThreadFunc)&threadLoop, this); + g_timeout_add(5, updateProperties, this); } OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config) - : AbstractSource(re, config),obd2Connected(Obd2Connected,false) + : AbstractSource(re, config), obd2Connected(Obd2Connected,false) { - bool success = VehicleProperty::registerProperty(Obd2Connected,[](){ return new Obd2ConnectType(Obd2Connected,false); }); + bool success = VehicleProperty::registerProperty(Obd2Connected, [](){ return new Obd2ConnectType(Obd2Connected, false); }); if(!success) { diff --git a/plugins/opencvlux/CMakeLists.txt b/plugins/opencvlux/CMakeLists.txt index acb48ed7..f7ef01c7 100644 --- a/plugins/opencvlux/CMakeLists.txt +++ b/plugins/opencvlux/CMakeLists.txt @@ -1,15 +1,19 @@ if(opencvlux_plugin) +set(qtmainloop "ON") + find_package(OpenCV REQUIRED) if(OpenCV_LIBS) - message(STATUS "opencv found") + message(STATUS "opencv found: ${OpenCV_INCLUDE_DIRS}") else(OpenCV_LIBS) message(FATAL_ERROR "opencv missing. please install opencv") endif(OpenCV_LIBS) option(ocl "enable opencl" OFF) +add_definitions(-DCV_DATA="${OpenCV_CONFIG_PATH}") + if(ocl) message(STATUS "found opencv ocl headers. enabling opencl support. ${ocl}") add_definitions(-DOPENCL) @@ -37,6 +41,7 @@ if(Qt5Core_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") message(STATUS "size of void_p: ${CMAKE_SIZEOF_VOID_P}") add_definitions(${Qt5Core_DEFINITIONS}) + add_definitions(-DQT_NO_KEYWORDS) endif(Qt5Core_FOUND) set(CMAKE_AUTOMOC ON) diff --git a/plugins/opencvlux/README b/plugins/opencvlux/README index 014dd8dd..9d88b6f4 100644 --- a/plugins/opencvlux/README +++ b/plugins/opencvlux/README @@ -69,11 +69,7 @@ Default: "255" "opencl" (experimental) Use a specialized CPU/GPU device to calculate the mean pixel intensity. This will only work if OpenCV -was compiled with OpenCL support. This plugin looks for the OpenCV ocl headers and adds support at -compile time. - -NOTE: This option has not been tested because at implementation, OpenCL 1.2 was not available from devices -on-hand. +was compiled with OpenCL support. To enable openCL, pass -Docl=ON to cmake. Default: "false" @@ -85,3 +81,39 @@ NOTE: this does not appear to have a noticable impact on processing given the wa this does however make memory usage explode. Default: "false" + +"logging" +Turn on video logging. + +Default: "false" + +"logfile" +File to encode video to. + +Default: "/tmp/video.avi" + +"codec" +Fourcc name of codec. See http://www.fourcc.org/codecs.php + +Default: "mjpg" + +"ddd" (experimental) +Driver Drowsiness Detection. For a driver facing camera, detect whether or not eyes are +open or closed. If closed for a period of time, DriverDrowsiness will change to "true". + +Default: "false" + + +AMB Properties: + +VideoLogging +Turn on and off video logging + +Type: bool +Access: readwrite + +DriverDrowsiness +True if the driver has been detected drowsy. + +Type: bool +Access: readonly diff --git a/plugins/opencvlux/opencvluxplugin.cpp b/plugins/opencvlux/opencvluxplugin.cpp index d3874014..46fa62e6 100644 --- a/plugins/opencvlux/opencvluxplugin.cpp +++ b/plugins/opencvlux/opencvluxplugin.cpp @@ -19,9 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "opencvluxplugin.h" #include "timestamp.h" #include <listplusplus.h> +#include <superptr.hpp> #include <iostream> #include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/objdetect/objdetect.hpp> #include <QFuture> #include <QFutureWatcher> @@ -39,13 +41,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA using namespace std; const std::string VideoLogging = "VideoLogging"; +const std::string DriverDrowsiness = "DriverDrowsiness"; #include "debugout.h" extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config) { VehicleProperty::registerProperty(VideoLogging, [](){ - return new BasicPropertyType<bool>(VideoLogging,false); + return new BasicPropertyType<bool>(VideoLogging, false); + }); + + VehicleProperty::registerProperty(DriverDrowsiness, [](){ + return new OpenCvLuxPlugin::DriverDrowsinessType(DriverDrowsiness, false); }); return new OpenCvLuxPlugin(routingengine, config); @@ -54,7 +61,9 @@ extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<str OpenCvLuxPlugin::OpenCvLuxPlugin(AbstractRoutingEngine* re, map<string, string> config) :AbstractSource(re, config), lastLux(0), speed(0), latitude(0), longitude(0), extBrightness(new VehicleProperty::ExteriorBrightnessType(0)) { - shared = new Shared; + driverDrowsiness = amb::make_unique(new DriverDrowsinessType(DriverDrowsiness, false)); + + shared = amb::make_unique(new Shared); shared->parent = this; shared->m_capture = NULL; @@ -65,6 +74,7 @@ OpenCvLuxPlugin::OpenCvLuxPlugin(AbstractRoutingEngine* re, map<string, string> shared->useOpenCl = false; shared->useCuda = false; shared->loggingOn = false; + shared->ddd = false; shared->fps=30; device="0"; @@ -115,6 +125,9 @@ OpenCvLuxPlugin::OpenCvLuxPlugin(AbstractRoutingEngine* re, map<string, string> { #ifdef OPENCL shared->useOpenCl = config["opencl"] == "true"; +#else + DebugOut(DebugOut::Warning) << "You really don't have openCL support. Disabling." << endl; + shared->useOpenCl = false; #endif } @@ -126,6 +139,16 @@ OpenCvLuxPlugin::OpenCvLuxPlugin(AbstractRoutingEngine* re, map<string, string> #endif } + if(config.find("ddd") != config.end()) + { + shared->ddd = config["ddd"] == "true"; + } + + if(config.find("logging") != config.end()) + { + shared->loggingOn = config["logging"] == "true"; + } + #ifdef OPENCL if(shared->useOpenCl) @@ -185,14 +208,46 @@ OpenCvLuxPlugin::OpenCvLuxPlugin(AbstractRoutingEngine* re, map<string, string> } #endif + if(shared->ddd) + { +#ifdef OPENCL + if(shared->useOpenCl) + { + faceCascade = amb::make_unique(new cv::ocl::OclCascadeClassifier()); + eyeCascade = amb::make_unique(new cv::ocl::OclCascadeClassifier()); + } + else +#endif + { + faceCascade = amb::make_unique(new cv::CascadeClassifier()); + eyeCascade = amb::make_unique(new cv::CascadeClassifier()); + } + + std::string faceFile = CV_DATA "/haarcascades/haarcascade_frontalface_alt.xml"; + if(!faceCascade->load(faceFile)) + { + DebugOut(DebugOut::Warning) << "Could not load face cascade: " << faceFile <<". Disabling ddd" << endl; + shared->ddd = false; + } + + std::string eyeFile = CV_DATA "/haarcascades/haarcascade_eye_tree_eyeglasses.xml"; + + if(!eyeCascade->load(eyeFile)) + { + DebugOut(DebugOut::Warning) << "Could not load eye cascade: " << eyeFile <<". Disabling ddd" << endl; + shared->ddd = false; + } + + } + routingEngine->subscribeToProperty(VehicleProperty::VehicleSpeed, this); - routingEngine->subscribeToProperty(VehicleProperty::Latitude,this); + routingEngine->subscribeToProperty(VehicleProperty::Latitude, this); routingEngine->subscribeToProperty(VehicleProperty::Longitude, this); } OpenCvLuxPlugin::~OpenCvLuxPlugin() { - delete shared->mWriter; + } const string OpenCvLuxPlugin::uuid() @@ -211,7 +266,7 @@ void OpenCvLuxPlugin::getPropertyAsync(AsyncPropertyReply *reply) /// we want to turn on the camera for one shot to get an image and determine the intensity if(init()) - grabImage(shared); + grabImage(shared.get()); } if(reply->property == VehicleProperty::ExteriorBrightness) @@ -263,7 +318,7 @@ void OpenCvLuxPlugin::subscribeToPropertyChanges(VehicleProperty::Property prope if(!shared->mRequests.size()) { if(init()) - g_timeout_add(1000 / shared->fps, grabImage, shared); + g_timeout_add(1000 / shared->fps, grabImage, shared.get()); } shared->mRequests.push_back(property); @@ -278,6 +333,7 @@ PropertyList OpenCvLuxPlugin::supported() { PropertyList props; props.push_back(VehicleProperty::ExteriorBrightness); + props.push_back(DriverDrowsiness); props.push_back(VideoLogging); return props; @@ -323,9 +379,12 @@ static int grabImage(void *data) } else { - *(shared->m_capture) >> m_image; + *(shared->m_capture.get()) >> m_image; } + if(shared->ddd) + shared->parent->detectEyes(m_image); + if(shared->threaded) { QFutureWatcher<uint> *watcher = new QFutureWatcher<uint>(); @@ -413,14 +472,14 @@ bool OpenCvLuxPlugin::init() { if(!shared->m_capture && shared->kinect) { - shared->m_capture = new cv::VideoCapture(CV_CAP_OPENNI); + shared->m_capture = amb::make_unique(new cv::VideoCapture(CV_CAP_OPENNI)); } else if(!shared->m_capture) { if(device == "") - shared->m_capture = new cv::VideoCapture(0); + shared->m_capture = amb::make_unique(new cv::VideoCapture(0)); else - shared->m_capture = new cv::VideoCapture(atoi(device.c_str())); + shared->m_capture = amb::make_unique(new cv::VideoCapture(atoi(device.c_str()))); } if(!shared->m_capture->isOpened()) @@ -450,9 +509,7 @@ bool OpenCvLuxPlugin::init() boost::algorithm::to_upper(codec); - if(shared->mWriter) delete shared->mWriter; - - shared->mWriter = new cv::VideoWriter(filename, CV_FOURCC(codec.at(0), codec.at(1), codec.at(2), codec.at(3)),30,s); + shared->mWriter = amb::make_unique(new cv::VideoWriter(filename, CV_FOURCC(codec.at(0), codec.at(1), codec.at(2), codec.at(3)),30,s)); } DebugOut()<<"camera frame width: "<<shared->m_capture->get(CV_CAP_PROP_FRAME_WIDTH)<<endl; @@ -470,8 +527,6 @@ void OpenCvLuxPlugin::writeVideoFrame(cv::Mat f) if(shared->loggingOn && speed > 0) { - - cv::Mat frame; f.copyTo(frame); @@ -511,8 +566,8 @@ void OpenCvLuxPlugin::writeVideoFrame(cv::Mat f) cv::putText(frame, datestr.str(), dateOrg, fontFace, fontScale, cv::Scalar::all(255), thickness, 8); - (*shared->mWriter)<<frame; - (*shared->mWriter)<<frame; + (*shared->mWriter) << frame; + (*shared->mWriter) << frame; } } @@ -611,7 +666,8 @@ TrafficLight::Color detectLight(cv::Mat img, OpenCvLuxPlugin::Shared *shared) } else if(avgPixel[0] > 128 && avgPixel[1] < 128 && avgPixel[2] < 128) { - DebugOut(1)<<"Bluel Light!!!"<<endl; + DebugOut(1)<<"Yellow Light!!!"<<endl; + return TrafficLight::Yellow; } } catch(...) @@ -623,6 +679,72 @@ TrafficLight::Color detectLight(cv::Mat img, OpenCvLuxPlugin::Shared *shared) cv::namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); cv::imshow( "Hough Circle Transform Demo", img ); +} +void OpenCvLuxPlugin::detectEyes(cv::Mat frame) +{ + if(frame.empty()) + return; + + bool hasEyes = false; + std::vector<cv::Rect> faces; + cv::Mat frameGray; +#ifdef OPENCL + cv::ocl::oclMat gray2; +#endif + + if(shared->useOpenCl) + { +#ifdef OPENCL + cv::ocl::oclMat src(frame); + cv::ocl::cvtColor(src, gray2, CV_BGR2GRAY); + cv::ocl::equalizeHist(gray2, gray2); + cv::ocl::OclCascadeClassifier* fc = static_cast<cv::ocl::OclCascadeClassifier*>(faceCascade.get()); + fc->detectMultiScale(gray2, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30)); +#endif + } + else + { + cv::cvtColor(frame, frameGray, CV_BGR2GRAY); + cv::equalizeHist(frameGray, frameGray); + faceCascade->detectMultiScale(frameGray, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30)); + } + + for( size_t i = 0; i < faces.size(); i++ ) + { + cv::Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 ); + cv::ellipse( frame, center, cv::Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, cv::Scalar( 255, 0, 255 ), 4, 8, 0 ); + + std::vector<cv::Rect> eyes; + + if(shared->useOpenCl) + { +#ifdef OPENCL + cv::ocl::oclMat faceROI = gray2(faces[i]); + cv::ocl::OclCascadeClassifier* ec = static_cast<cv::ocl::OclCascadeClassifier*>(eyeCascade.get()); + ec->detectMultiScale( faceROI, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30) ); +#endif + } + else + { + cv::Mat faceROI = frameGray(faces[i]); + eyeCascade->detectMultiScale( faceROI, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30) ); + } + + if(eyes.size()) + { + hasEyes = true; + DebugOut() << "Number of eyes: " << eyes.size() << endl; + } + + for( size_t j = 0; j < eyes.size(); j++ ) + { + cv::Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 ); + int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 ); + cv::circle( frame, center, radius, cv::Scalar( 255, 0, 0 ), 4, 8, 0 ); + } + } + + routingEngine->updateProperty(driverDrowsiness.get(),this->uuid()); } diff --git a/plugins/opencvlux/opencvluxplugin.h b/plugins/opencvlux/opencvluxplugin.h index 5f197711..9bb79302 100644 --- a/plugins/opencvlux/opencvluxplugin.h +++ b/plugins/opencvlux/opencvluxplugin.h @@ -36,10 +36,12 @@ class OpenCvLuxPlugin: public QObject, public AbstractSource Q_OBJECT public: + typedef BasicPropertyType<bool> DriverDrowsinessType; + struct Shared { - cv::VideoCapture *m_capture; - cv::VideoWriter *mWriter; + std::unique_ptr<cv::VideoCapture> m_capture; + std::unique_ptr<cv::VideoWriter> mWriter; PropertyList mRequests; OpenCvLuxPlugin* parent; @@ -51,6 +53,7 @@ public: int pixelLowerBound; int pixelUpperBound; bool loggingOn; + bool ddd; }; OpenCvLuxPlugin(AbstractRoutingEngine* re, map<string, string> config); @@ -75,6 +78,8 @@ public: void writeVideoFrame(cv::Mat frame); + void detectEyes(cv::Mat frame); + public Q_SLOTS: void imgProcResult(); @@ -83,6 +88,8 @@ private: /// methods: bool init(); private: + + uint speed; uint latitude; uint longitude; @@ -93,8 +100,13 @@ private: std::unique_ptr<VehicleProperty::ExteriorBrightnessType> extBrightness; - Shared* shared; + std::unique_ptr<Shared> shared; QMutex mutex; + + std::unique_ptr<cv::CascadeClassifier> faceCascade; + std::unique_ptr<cv::CascadeClassifier> eyeCascade; + + std::unique_ptr<DriverDrowsinessType> driverDrowsiness; }; static int grabImage(void *data); @@ -113,4 +125,5 @@ enum Color TrafficLight::Color detectLight(cv::Mat img, OpenCvLuxPlugin::Shared* shared); + #endif // EXAMPLEPLUGIN_H diff --git a/xwalk/CMakeLists.txt b/xwalk/CMakeLists.txt new file mode 100644 index 00000000..4cfd571b --- /dev/null +++ b/xwalk/CMakeLists.txt @@ -0,0 +1,23 @@ +if(xwalk_vehicle_extension) + +pkg_check_modules(gio REQUIRED gio-2.0) + +set(vehicle_api_headers vehicle.h vehicle_instance.h vehicle_extension.h common/extension.h picojson.h common/utils.h common/virtual_fs.h + common/XW_Extension_EntryPoints.h common/XW_Extension.h common/XW_Permissions.h common/XW_Extension_Runtime.h common/XW_Extension_SyncMessage.h) +set(vehicle_api_sources vehicle.cc vehicle_extension.cc vehicle_instance.cc common/extension.cc vehicle_api.cc) + +add_library(vehicle_extension MODULE ${vehicle_api_sources}) + +include_directories(${include_dirs} ${CMAKE_CURRENT_SOURCE_DIR}/) +target_link_libraries(vehicle_extension ${link_libraries} amb ${gio_LIBRARIES} -L${CMAKE_CURRENT_BINARY_DIR}/lib) + +add_custom_command(OUTPUT genjs2cc COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/generate_api.py ${CMAKE_CURRENT_SOURCE_DIR}/vehicle_api.js kSource_vehicle_api ${CMAKE_CURRENT_SOURCE_DIR}/vehicle_api.cc ) +add_custom_target(js3cc DEPENDS genjs2cc) +add_dependencies(vehicle_extension js3cc) + +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/vehicle_api.js ${CMAKE_CURRENT_SOURCE_DIR}/vehicle_api.js @ONLY) +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/vehicle.html ${CMAKE_CURRENT_SOURCE_DIR}/vehicle.html @ONLY) + +install(TARGETS vehicle_extension LIBRARY DESTINATION "${LIB_INSTALL_DIR}/${XWALK_EXTENSION_PATH}") +install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/vehicle.html DESTINATION /usr/share/automotive-message-broker/xwalk/examples) +endif(xwalk_vehicle_extension) diff --git a/xwalk/LICENSE b/xwalk/LICENSE new file mode 100644 index 00000000..ac380b1a --- /dev/null +++ b/xwalk/LICENSE @@ -0,0 +1,27 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Intel Corporation nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/xwalk/common/XW_Extension.h b/xwalk/common/XW_Extension.h new file mode 100644 index 00000000..174915ad --- /dev/null +++ b/xwalk/common/XW_Extension.h @@ -0,0 +1,185 @@ +// Copyright (c) 2013 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 XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ + +// Crosswalk Extensions are modules of code loaded by Crosswalk runtime that +// allow extending its capabilities. The extension is expected to define a +// XW_Initialize() function as declared below, get the interfaces it need to +// use and register to whatever callbacks it needs, then return XW_OK. +// +// The Extension is represented by the type XW_Extension. Each extension +// loaded may be used multiple times for different pages, so to each execution +// there will be an associated XW_Instance. A reasonable analogy is that the +// XW_Extension represent a "class", and have concrete instances running. +// +// An interface is a struct with a set of functions, provided by Crosswalk, +// that allow the extension code to interact with the web content. Certain +// functions in an interface are used to register callbacks, so that Crosswalk +// can call the extension at specific situations. +// +// Crosswalk won't call an extension's XW_Initialize() multiple times in the +// same process. + +#ifdef __cplusplus +extern "C" { +#endif + +#if __GNUC__ >= 4 +#define XW_EXPORT __attribute__ ((visibility("default"))) +#elif defined(_MSC_VER) +#define XW_EXPORT __declspec(dllexport) +#endif + +#include <stdint.h> + + +// XW_Extension is used to identify your extension when calling functions from +// the API. You should always use the XW_Extension received at XW_Initialize(). +// +// XW_Instance is used to identify different web contents using your +// extension. Each time a new web content is created you can be notified +// registering the XW_CreatedInstanceCallback, that receives the new +// XW_Instance. When interacting with an Instance (for example to post a +// message), you should pass the corresponding XW_Instance. +// +// In both types the zero value is never used by Crosswalk, so can be used to +// initialize variables. +typedef int32_t XW_Extension; +typedef int32_t XW_Instance; + +enum { + XW_OK = 0, + XW_ERROR = -1 +}; + +// Returns a struct containing functions to be used by the extension. Those +// structs can be stored statically and used until the extension is unloaded. +// Extensions should use definitions like XW_CORE_INTERFACE, instead of using +// the versioned definition or the literal string. Returns NULL if the +// interface is not supported. +typedef const void* (*XW_GetInterface)(const char* interface_name); + + +typedef int32_t (*XW_Initialize_Func)(XW_Extension extension, + XW_GetInterface get_interface); + +// XW_Initialize is called after the extension code is loaded. The 'extension' +// value should be used in further calls that expect XW_Extension argument. +// +// The 'get_interface' function should be used to get access to functions that +// interact with the web content. It is only valid during the execution of the +// XW_Initialize() function. +// +// This function should return XW_OK when the extension was succesfully +// loaded, otherwise XW_ERROR. +XW_EXPORT int32_t XW_Initialize(XW_Extension extension, + XW_GetInterface get_interface); + + +// +// XW_CORE_INTERFACE: Basic functionality for Crosswalk Extensions. All +// extensions should use this interface to set at least their name. +// + +#define XW_CORE_INTERFACE_1 "XW_CoreInterface_1" +#define XW_CORE_INTERFACE XW_CORE_INTERFACE_1 + +typedef void (*XW_CreatedInstanceCallback)(XW_Instance instance); +typedef void (*XW_DestroyedInstanceCallback)(XW_Instance instance); +typedef void (*XW_ShutdownCallback)(XW_Extension extension); + +struct XW_CoreInterface_1 { + // Set the name of the extension. It is used as the namespace for the + // JavaScript code exposed by the extension. So extension named + // 'my_extension', will expose its JavaScript functionality inside + // the 'my_extension' namespace. + // + // This function should be called only during XW_Initialize(). + void (*SetExtensionName)(XW_Extension extension, const char* name); + + // Set the JavaScript code loaded in the web content when the extension is + // used. This can be used together with the messaging mechanism to implement + // a higher-level API that posts messages to extensions, see + // XW_MESSAGING_INTERFACE below. + // + // The code will be executed inside a JS function context with the following + // objects available: + // + // - exports: this object should be filled with properties and functions + // that will be exposed in the namespace associated with this + // extension. + // + // - extension.postMessage(): post a string message to the extension native + // code. See below for details. + // - extension.setMessageListener(): allow setting a callback that is called + // when the native code sends a message + // to JavaScript. Callback takes a string. + // + // This function should be called only during XW_Initialize(). + void (*SetJavaScriptAPI)(XW_Extension extension, const char* api); + + // Register callbacks that are called when an instance of this extension + // is created or destroyed. Everytime a new web content is loaded, it will + // get a new associated instance. + // + // This function should be called only during XW_Initialize(). + void (*RegisterInstanceCallbacks)(XW_Extension extension, + XW_CreatedInstanceCallback created, + XW_DestroyedInstanceCallback destroyed); + + // Register a callback to be executed when the extension will be unloaded. + // + // This function should be called only during XW_Initialize(). + void (*RegisterShutdownCallback)(XW_Extension extension, + XW_ShutdownCallback shutdown_callback); + + // These two functions are conveniences used to associated arbitrary data + // with a given XW_Instance. They can be used only with instances that were + // created but not yet completely destroyed. GetInstanceData() can be used + // during the destroyed instance callback. If not instance data was set, + // getting it returns NULL. + void (*SetInstanceData)(XW_Instance instance, void* data); + void* (*GetInstanceData)(XW_Instance instance); +}; + +typedef struct XW_CoreInterface_1 XW_CoreInterface; + + +// +// XW_MESSAGING_INTERFACE: Exchange asynchronous messages with JavaScript +// code provided by extension. +// + +#define XW_MESSAGING_INTERFACE_1 "XW_MessagingInterface_1" +#define XW_MESSAGING_INTERFACE XW_MESSAGING_INTERFACE_1 + +typedef void (*XW_HandleMessageCallback)(XW_Instance instance, + const char* message); + +struct XW_MessagingInterface_1 { + // Register a callback to be called when the JavaScript code associated + // with the extension posts a message. Note that the callback will be called + // with the XW_Instance that posted the message as well as the message + // contents. + void (*Register)(XW_Extension extension, + XW_HandleMessageCallback handle_message); + + // Post a message to the web content associated with the instance. To + // receive this message the extension's JavaScript code should set a + // listener using extension.setMessageListener() function. + // + // This function is thread-safe and can be called until the instance is + // destroyed. + void (*PostMessage)(XW_Instance instance, const char* message); +}; + +typedef struct XW_MessagingInterface_1 XW_MessagingInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ diff --git a/xwalk/common/XW_Extension_EntryPoints.h b/xwalk/common/XW_Extension_EntryPoints.h new file mode 100644 index 00000000..54532a91 --- /dev/null +++ b/xwalk/common/XW_Extension_EntryPoints.h @@ -0,0 +1,49 @@ +// Copyright (c) 2013 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 XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_INTERNAL_ENTRY_POINTS_INTERFACE_1 \ + "XW_Internal_EntryPointsInterface_1" +#define XW_INTERNAL_ENTRY_POINTS_INTERFACE \ + XW_INTERNAL_ENTRY_POINTS_INTERFACE_1 + +// +// XW_INTERNAL_ENTRY_POINTS_INTERFACE: provides a way for extensions to add +// more information about its implementation. For now, allow extensions to +// specify more objects that the access should cause the extension to be +// loaded. +// + +struct XW_Internal_EntryPointsInterface_1 { + // Register extra entry points for this extension. An "extra" entry points + // are objects outside the implicit namespace for which the extension should + // be loaded when they are touched. + // + // This function should be called only during XW_Initialize(). + void (*SetExtraJSEntryPoints)(XW_Extension extension, + const char** entry_points); +}; + +typedef struct XW_Internal_EntryPointsInterface_1 + XW_Internal_EntryPointsInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_ + diff --git a/xwalk/common/XW_Extension_Permissions.h b/xwalk/common/XW_Extension_Permissions.h new file mode 100644 index 00000000..d25484ea --- /dev/null +++ b/xwalk/common/XW_Extension_Permissions.h @@ -0,0 +1,41 @@ +// 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 XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_INTERNAL_PERMISSIONS_INTERFACE_1 \ + "XW_Internal_PermissionsInterface_1" +#define XW_INTERNAL_PERMISSIONS_INTERFACE \ + XW_INTERNAL_PERMISSIONS_INTERFACE_1 + +// +// XW_INTERNAL_PERMISSIONS_INTERFACE: provides a way for extensions +// check if they have the proper permissions for certain APIs. +// + +struct XW_Internal_PermissionsInterface_1 { + int (*CheckAPIAccessControl)(XW_Extension extension, const char* api_name); + int (*RegisterPermissions)(XW_Extension extension, const char* perm_table); +}; + +typedef struct XW_Internal_PermissionsInterface_1 + XW_Internal_PermissionsInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_ diff --git a/xwalk/common/XW_Extension_Runtime.h b/xwalk/common/XW_Extension_Runtime.h new file mode 100644 index 00000000..f5858f3e --- /dev/null +++ b/xwalk/common/XW_Extension_Runtime.h @@ -0,0 +1,44 @@ +// Copyright (c) 2013 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 XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define XW_INTERNAL_RUNTIME_INTERFACE_1 \ + "XW_Internal_RuntimeInterface_1" +#define XW_INTERNAL_RUNTIME_INTERFACE \ + XW_INTERNAL_RUNTIME_INTERFACE_1 + +// +// XW_INTERNAL_RUNTIME_INTERFACE: allow extensions to gather information +// from the runtime. +// + +struct XW_Internal_RuntimeInterface_1 { + void (*GetRuntimeVariableString)(XW_Extension extension, + const char* key, + char* value, + size_t value_len); +}; + +typedef struct XW_Internal_RuntimeInterface_1 + XW_Internal_RuntimeInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_ + diff --git a/xwalk/common/XW_Extension_SyncMessage.h b/xwalk/common/XW_Extension_SyncMessage.h new file mode 100644 index 00000000..4eddbf9b --- /dev/null +++ b/xwalk/common/XW_Extension_SyncMessage.h @@ -0,0 +1,48 @@ +// Copyright (c) 2013 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 XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_ +#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_ + +// NOTE: This file and interfaces marked as internal are not considered stable +// and can be modified in incompatible ways between Crosswalk versions. + +#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_ +#error "You should include XW_Extension.h before this file" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// +// XW_INTERNAL_SYNC_MESSAGING_INTERFACE: allow JavaScript code to send a +// synchronous message to extension code and block until response is +// available. The response is made available by calling the SetSyncReply +// function, that can be done from outside the context of the SyncMessage +// handler. +// + +#define XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1 \ + "XW_InternalSyncMessagingInterface_1" +#define XW_INTERNAL_SYNC_MESSAGING_INTERFACE \ + XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1 + +typedef void (*XW_HandleSyncMessageCallback)(XW_Instance instance, + const char* message); + +struct XW_Internal_SyncMessagingInterface_1 { + void (*Register)(XW_Extension extension, + XW_HandleSyncMessageCallback handle_sync_message); + void (*SetSyncReply)(XW_Instance instance, const char* reply); +}; + +typedef struct XW_Internal_SyncMessagingInterface_1 + XW_Internal_SyncMessagingInterface; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_ diff --git a/xwalk/common/extension.cc b/xwalk/common/extension.cc new file mode 100644 index 00000000..168483a3 --- /dev/null +++ b/xwalk/common/extension.cc @@ -0,0 +1,212 @@ +// Copyright (c) 2013 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 "common/extension.h" + +#include <assert.h> +#include <iostream> +#include <vector> + +namespace { + +common::Extension* g_extension = NULL; +XW_Extension g_xw_extension = 0; + +const XW_CoreInterface* g_core = NULL; +const XW_MessagingInterface* g_messaging = NULL; +const XW_Internal_SyncMessagingInterface* g_sync_messaging = NULL; +const XW_Internal_EntryPointsInterface* g_entry_points = NULL; +const XW_Internal_RuntimeInterface* g_runtime = NULL; +const XW_Internal_PermissionsInterface* g_permission = NULL; + +bool InitializeInterfaces(XW_GetInterface get_interface) { + g_core = reinterpret_cast<const XW_CoreInterface*>( + get_interface(XW_CORE_INTERFACE)); + if (!g_core) { + std::cerr << "Can't initialize extension: error getting Core interface.\n"; + return false; + } + + g_messaging = reinterpret_cast<const XW_MessagingInterface*>( + get_interface(XW_MESSAGING_INTERFACE)); + if (!g_messaging) { + std::cerr << + "Can't initialize extension: error getting Messaging interface.\n"; + return false; + } + + g_sync_messaging = + reinterpret_cast<const XW_Internal_SyncMessagingInterface*>( + get_interface(XW_INTERNAL_SYNC_MESSAGING_INTERFACE)); + if (!g_sync_messaging) { + std::cerr << + "Can't initialize extension: error getting SyncMessaging interface.\n"; + return false; + } + + g_entry_points = reinterpret_cast<const XW_Internal_EntryPointsInterface*>( + get_interface(XW_INTERNAL_ENTRY_POINTS_INTERFACE)); + if (!g_entry_points) { + std::cerr << "NOTE: Entry points interface not available in this version " + << "of Crosswalk, ignoring entry point data for extensions.\n"; + } + + g_runtime = reinterpret_cast<const XW_Internal_RuntimeInterface*>( + get_interface(XW_INTERNAL_RUNTIME_INTERFACE)); + if (!g_runtime) { + std::cerr << "NOTE: runtime interface not available in this version " + << "of Crosswalk, ignoring runtime variables for extensions.\n"; + } + + g_permission = reinterpret_cast<const XW_Internal_PermissionsInterface*>( + get_interface(XW_INTERNAL_PERMISSIONS_INTERFACE)); + if (!g_permission) { + std::cerr << "NOTE: permission interface not available in this version " + << "of Crosswalk, ignoring permission for extensions.\n"; + } + + return true; +} + +} // namespace + +int32_t XW_Initialize(XW_Extension extension, XW_GetInterface get_interface) { + assert(extension); + g_xw_extension = extension; + + if (!InitializeInterfaces(get_interface)) + return XW_ERROR; + + g_extension = CreateExtension(); + if (!g_extension) { + std::cerr << "Can't initialize extension: " + << "create extension returned NULL.\n"; + return XW_ERROR; + } + + using common::Extension; + g_core->RegisterShutdownCallback(g_xw_extension, Extension::OnShutdown); + g_core->RegisterInstanceCallbacks( + g_xw_extension, Extension::OnInstanceCreated, + Extension::OnInstanceDestroyed); + g_messaging->Register(g_xw_extension, Extension::HandleMessage); + g_sync_messaging->Register(g_xw_extension, Extension::HandleSyncMessage); + return XW_OK; +} + +namespace common { + +Extension::Extension() {} + +Extension::~Extension() {} + +void Extension::SetExtensionName(const char* name) { + g_core->SetExtensionName(g_xw_extension, name); +} + +void Extension::SetJavaScriptAPI(const char* api) { + g_core->SetJavaScriptAPI(g_xw_extension, api); +} + +void Extension::SetExtraJSEntryPoints(const char** entry_points) { + if (g_entry_points) + g_entry_points->SetExtraJSEntryPoints(g_xw_extension, entry_points); +} + +bool Extension::RegisterPermissions(const char* perm_table) { + if (g_permission) + return g_permission->RegisterPermissions(g_xw_extension, perm_table); + return false; +} + +bool Extension::CheckAPIAccessControl(const char* api_name) { + if (g_permission) + return g_permission->CheckAPIAccessControl(g_xw_extension, api_name); + return false; +} + +Instance* Extension::CreateInstance() { + return NULL; +} + +std::string Extension::GetRuntimeVariable(const char* var_name, unsigned len) { + if (!g_runtime) + return ""; + + std::vector<char> res(len + 1, 0); + g_runtime->GetRuntimeVariableString(g_xw_extension, var_name, &res[0], len); + return std::string(res.begin(), res.end()); +} + +// static +void Extension::OnShutdown(XW_Extension) { + delete g_extension; + g_extension = NULL; +} + +// static +void Extension::OnInstanceCreated(XW_Instance xw_instance) { + assert(!g_core->GetInstanceData(xw_instance)); + Instance* instance = g_extension->CreateInstance(); + if (!instance) + return; + instance->xw_instance_ = xw_instance; + g_core->SetInstanceData(xw_instance, instance); + instance->Initialize(); +} + +// static +void Extension::OnInstanceDestroyed(XW_Instance xw_instance) { + Instance* instance = + reinterpret_cast<Instance*>(g_core->GetInstanceData(xw_instance)); + if (!instance) + return; + instance->xw_instance_ = 0; + delete instance; +} + +// static +void Extension::HandleMessage(XW_Instance xw_instance, const char* msg) { + Instance* instance = + reinterpret_cast<Instance*>(g_core->GetInstanceData(xw_instance)); + if (!instance) + return; + instance->HandleMessage(msg); +} + +// static +void Extension::HandleSyncMessage(XW_Instance xw_instance, const char* msg) { + Instance* instance = + reinterpret_cast<Instance*>(g_core->GetInstanceData(xw_instance)); + if (!instance) + return; + instance->HandleSyncMessage(msg); +} + +Instance::Instance() + : xw_instance_(0) {} + +Instance::~Instance() { + assert(xw_instance_ == 0); +} + +void Instance::PostMessage(const char* msg) { + if (!xw_instance_) { + std::cerr << "Ignoring PostMessage() in the constructor or after the " + << "instance was destroyed."; + return; + } + g_messaging->PostMessage(xw_instance_, msg); +} + +void Instance::SendSyncReply(const char* reply) { + if (!xw_instance_) { + std::cerr << "Ignoring SendSyncReply() in the constructor or after the " + << "instance was destroyed."; + return; + } + g_sync_messaging->SetSyncReply(xw_instance_, reply); +} + +} // namespace common diff --git a/xwalk/common/extension.h b/xwalk/common/extension.h new file mode 100644 index 00000000..66d8bef0 --- /dev/null +++ b/xwalk/common/extension.h @@ -0,0 +1,96 @@ +// Copyright (c) 2013 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 COMMON_EXTENSION_H_ +#define COMMON_EXTENSION_H_ + +// This is a C++ wrapper over Crosswalk Extension C API. It implements once the +// boilerplate for the common case of mapping XW_Extension and XW_Instance to +// objects of their own. The wrapper deals automatically with creating and +// destroying the objects. +// +// Extension object lives during the lifetime of the extension, and when the +// extension process is properly shutdown, it's destructor will be +// called. Instance objects (there can be many) live during the lifetime of a +// script context associated with a frame in the page. These objects serves as +// storage points for extension specific objects, use them for that. + +#include <sys/types.h> + +#include <string> + +#include "common/XW_Extension.h" +#include "common/XW_Extension_EntryPoints.h" +#include "common/XW_Extension_Permissions.h" +#include "common/XW_Extension_Runtime.h" +#include "common/XW_Extension_SyncMessage.h" + +namespace common { + +class Instance; +class Extension; + +} // namespace common + + +// This function should be implemented by each extension and should return +// an appropriate Extension subclass. +common::Extension* CreateExtension(); + + +namespace common { + +class Extension { + public: + Extension(); + virtual ~Extension(); + + // These should be called in the subclass constructor. + void SetExtensionName(const char* name); + void SetJavaScriptAPI(const char* api); + void SetExtraJSEntryPoints(const char** entry_points); + bool RegisterPermissions(const char* perm_table); + + // This API should be called in the message handler of extension + bool CheckAPIAccessControl(const char* api_name); + + virtual Instance* CreateInstance(); + + static std::string GetRuntimeVariable(const char* var_name, unsigned len); + + private: + friend int32_t ::XW_Initialize(XW_Extension extension, + XW_GetInterface get_interface); + + // XW_Extension callbacks. + static void OnShutdown(XW_Extension xw_extension); + static void OnInstanceCreated(XW_Instance xw_instance); + static void OnInstanceDestroyed(XW_Instance xw_instance); + static void HandleMessage(XW_Instance xw_instance, const char* msg); + static void HandleSyncMessage(XW_Instance xw_instance, const char* msg); +}; + +class Instance { + public: + Instance(); + virtual ~Instance(); + + void PostMessage(const char* msg); + void SendSyncReply(const char* reply); + + virtual void Initialize() {} + virtual void HandleMessage(const char* msg) = 0; + virtual void HandleSyncMessage(const char* msg) {} + + XW_Instance xw_instance() const { return xw_instance_; } + + private: + friend class Extension; + + XW_Instance xw_instance_; +}; + +} // namespace common + +#endif // COMMON_EXTENSION_H_ diff --git a/xwalk/common/picojson.h b/xwalk/common/picojson.h new file mode 100644 index 00000000..9f983197 --- /dev/null +++ b/xwalk/common/picojson.h @@ -0,0 +1,1037 @@ +/* + * Copyright 2009-2010 Cybozu Labs, Inc. + * Copyright 2011 Kazuho Oku + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Cybozu Labs, Inc. + * + */ +#ifndef picojson_h +#define picojson_h + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <iterator> +#include <map> +#include <string> +#include <vector> + +#ifdef _MSC_VER + #define SNPRINTF _snprintf_s + #pragma warning(push) + #pragma warning(disable : 4244) // conversion from int to char +#else + #define SNPRINTF snprintf +#endif + +namespace picojson { + + enum { + null_type, + boolean_type, + number_type, + string_type, + array_type, + object_type + }; + + struct null {}; + + class value { + public: + typedef std::vector<value> array; + typedef std::map<std::string, value> object; + union _storage { + bool boolean_; + double number_; + std::string* string_; + array* array_; + object* object_; + }; + protected: + int type_; + _storage u_; + public: + value(); + value(int type, bool); + explicit value(bool b); + explicit value(double n); + explicit value(const std::string& s); + explicit value(const array& a); + explicit value(const object& o); + explicit value(const char* s); + value(const char* s, size_t len); + ~value(); + value(const value& x); + value& operator=(const value& x); + void swap(value& x); + template <typename T> bool is() const; + template <typename T> const T& get() const; + template <typename T> T& get(); + bool evaluate_as_boolean() const; + const value& get(size_t idx) const; + const value& get(const std::string& key) const; + bool contains(size_t idx) const; + bool contains(const std::string& key) const; + std::string to_str() const; + template <typename Iter> void serialize(Iter os) const; + std::string serialize() const; + private: + template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool + }; + + typedef value::array array; + typedef value::object object; + + inline value::value() : type_(null_type) {} + + inline value::value(int type, bool) : type_(type) { + switch (type) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(boolean_, false); + INIT(number_, 0.0); + INIT(string_, new std::string()); + INIT(array_, new array()); + INIT(object_, new object()); +#undef INIT + default: break; + } + } + + inline value::value(bool b) : type_(boolean_type) { + u_.boolean_ = b; + } + + inline value::value(double n) : type_(number_type) { + u_.number_ = n; + } + + inline value::value(const std::string& s) : type_(string_type) { + u_.string_ = new std::string(s); + } + + inline value::value(const array& a) : type_(array_type) { + u_.array_ = new array(a); + } + + inline value::value(const object& o) : type_(object_type) { + u_.object_ = new object(o); + } + + inline value::value(const char* s) : type_(string_type) { + u_.string_ = new std::string(s); + } + + inline value::value(const char* s, size_t len) : type_(string_type) { + u_.string_ = new std::string(s, len); + } + + inline value::~value() { + switch (type_) { +#define DEINIT(p) case p##type: delete u_.p; break + DEINIT(string_); + DEINIT(array_); + DEINIT(object_); +#undef DEINIT + default: break; + } + } + + inline value::value(const value& x) : type_(x.type_) { + switch (type_) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(string_, new std::string(*x.u_.string_)); + INIT(array_, new array(*x.u_.array_)); + INIT(object_, new object(*x.u_.object_)); +#undef INIT + default: + u_ = x.u_; + break; + } + } + + inline value& value::operator=(const value& x) { + if (this != &x) { + this->~value(); + new (this) value(x); + } + return *this; + } + + inline void value::swap(value& x) { + std::swap(type_, x.type_); + std::swap(u_, x.u_); + } + +#define IS(ctype, jtype) \ + template <> inline bool value::is<ctype>() const { \ + return type_ == jtype##_type; \ + } + IS(null, null) + IS(bool, boolean) + IS(int, number) + IS(double, number) + IS(std::string, string) + IS(array, array) + IS(object, object) +#undef IS + +#define GET(ctype, var) \ + template <> inline const ctype& value::get<ctype>() const { \ + assert("type mismatch! call vis<type>() before get<type>()" \ + && is<ctype>()); \ + return var; \ + } \ + template <> inline ctype& value::get<ctype>() { \ + assert("type mismatch! call is<type>() before get<type>()" \ + && is<ctype>()); \ + return var; \ + } + GET(bool, u_.boolean_) + GET(double, u_.number_) + GET(std::string, *u_.string_) + GET(array, *u_.array_) + GET(object, *u_.object_) +#undef GET + + inline bool value::evaluate_as_boolean() const { + switch (type_) { + case null_type: + return false; + case boolean_type: + return u_.boolean_; + case number_type: + return u_.number_ != 0; + case string_type: + return ! u_.string_->empty(); + default: + return true; + } + } + + inline const value& value::get(size_t idx) const { + static value s_null; + assert(is<array>()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; + } + + inline const value& value::get(const std::string& key) const { + static value s_null; + assert(is<object>()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; + } + + inline bool value::contains(size_t idx) const { + assert(is<array>()); + return idx < u_.array_->size(); + } + + inline bool value::contains(const std::string& key) const { + assert(is<object>()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end(); + } + + inline std::string value::to_str() const { + switch (type_) { + case null_type: return "null"; + case boolean_type: return u_.boolean_ ? "true" : "false"; + case number_type: { + char buf[256]; + double tmp; + SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); + return buf; + } + case string_type: return *u_.string_; + case array_type: return "array"; + case object_type: return "object"; + default: assert(0); +#ifdef _MSC_VER + __assume(0); +#endif + } + return std::string(); + } + + template <typename Iter> void copy(const std::string& s, Iter oi) { + std::copy(s.begin(), s.end(), oi); + } + + template <typename Iter> void serialize_str(const std::string& s, Iter oi) { + *oi++ = '"'; + for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { + switch (*i) { +#define MAP(val, sym) case val: copy(sym, oi); break + MAP('"', "\\\""); + MAP('\\', "\\\\"); + MAP('/', "\\/"); + MAP('\b', "\\b"); + MAP('\f', "\\f"); + MAP('\n', "\\n"); + MAP('\r', "\\r"); + MAP('\t', "\\t"); +#undef MAP + default: + if ((unsigned char)*i < 0x20 || *i == 0x7f) { + char buf[7]; + SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); + copy(buf, buf + 6, oi); + } else { + *oi++ = *i; + } + break; + } + } + *oi++ = '"'; + } + + template <typename Iter> void value::serialize(Iter oi) const { + switch (type_) { + case string_type: + serialize_str(*u_.string_, oi); + break; + case array_type: { + *oi++ = '['; + for (array::const_iterator i = u_.array_->begin(); + i != u_.array_->end(); + ++i) { + if (i != u_.array_->begin()) { + *oi++ = ','; + } + i->serialize(oi); + } + *oi++ = ']'; + break; + } + case object_type: { + *oi++ = '{'; + for (object::const_iterator i = u_.object_->begin(); + i != u_.object_->end(); + ++i) { + if (i != u_.object_->begin()) { + *oi++ = ','; + } + serialize_str(i->first, oi); + *oi++ = ':'; + i->second.serialize(oi); + } + *oi++ = '}'; + break; + } + default: + copy(to_str(), oi); + break; + } + } + + inline std::string value::serialize() const { + std::string s; + serialize(std::back_inserter(s)); + return s; + } + + template <typename Iter> class input { + protected: + Iter cur_, end_; + int last_ch_; + bool ungot_; + int line_; + public: + input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} + int getc() { + if (ungot_) { + ungot_ = false; + return last_ch_; + } + if (cur_ == end_) { + last_ch_ = -1; + return -1; + } + if (last_ch_ == '\n') { + line_++; + } + last_ch_ = *cur_++ & 0xff; + return last_ch_; + } + void ungetc() { + if (last_ch_ != -1) { + assert(! ungot_); + ungot_ = true; + } + } + Iter cur() const { return cur_; } + int line() const { return line_; } + void skip_ws() { + while (1) { + int ch = getc(); + if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + ungetc(); + break; + } + } + } + bool expect(int expect) { + skip_ws(); + if (getc() != expect) { + ungetc(); + return false; + } + return true; + } + bool match(const std::string& pattern) { + for (std::string::const_iterator pi(pattern.begin()); + pi != pattern.end(); + ++pi) { + if (getc() != *pi) { + ungetc(); + return false; + } + } + return true; + } + }; + + template<typename Iter> inline int _parse_quadhex(input<Iter> &in) { + int uni_ch = 0, hex; + for (int i = 0; i < 4; i++) { + if ((hex = in.getc()) == -1) { + return -1; + } + if ('0' <= hex && hex <= '9') { + hex -= '0'; + } else if ('A' <= hex && hex <= 'F') { + hex -= 'A' - 0xa; + } else if ('a' <= hex && hex <= 'f') { + hex -= 'a' - 0xa; + } else { + in.ungetc(); + return -1; + } + uni_ch = uni_ch * 16 + hex; + } + return uni_ch; + } + + template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) { + int uni_ch; + if ((uni_ch = _parse_quadhex(in)) == -1) { + return false; + } + if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { + if (0xdc00 <= uni_ch) { + // a second 16-bit of a surrogate pair appeared + return false; + } + // first 16-bit of surrogate pair, get the next one + if (in.getc() != '\\' || in.getc() != 'u') { + in.ungetc(); + return false; + } + int second = _parse_quadhex(in); + if (! (0xdc00 <= second && second <= 0xdfff)) { + return false; + } + uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); + uni_ch += 0x10000; + } + if (uni_ch < 0x80) { + out.push_back(uni_ch); + } else { + if (uni_ch < 0x800) { + out.push_back(0xc0 | (uni_ch >> 6)); + } else { + if (uni_ch < 0x10000) { + out.push_back(0xe0 | (uni_ch >> 12)); + } else { + out.push_back(0xf0 | (uni_ch >> 18)); + out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); + } + out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); + } + out.push_back(0x80 | (uni_ch & 0x3f)); + } + return true; + } + + template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) { + while (1) { + int ch = in.getc(); + if (ch < ' ') { + in.ungetc(); + return false; + } else if (ch == '"') { + return true; + } else if (ch == '\\') { + if ((ch = in.getc()) == -1) { + return false; + } + switch (ch) { +#define MAP(sym, val) case sym: out.push_back(val); break + MAP('"', '\"'); + MAP('\\', '\\'); + MAP('/', '/'); + MAP('b', '\b'); + MAP('f', '\f'); + MAP('n', '\n'); + MAP('r', '\r'); + MAP('t', '\t'); +#undef MAP + case 'u': + if (! _parse_codepoint(out, in)) { + return false; + } + break; + default: + return false; + } + } else { + out.push_back(ch); + } + } + return false; + } + + template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) { + if (! ctx.parse_array_start()) { + return false; + } + if (in.expect(']')) { + return true; + } + size_t idx = 0; + do { + if (! ctx.parse_array_item(in, idx)) { + return false; + } + idx++; + } while (in.expect(',')); + return in.expect(']'); + } + + template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) { + if (! ctx.parse_object_start()) { + return false; + } + if (in.expect('}')) { + return true; + } + do { + std::string key; + if (! in.expect('"') + || ! _parse_string(key, in) + || ! in.expect(':')) { + return false; + } + if (! ctx.parse_object_item(in, key)) { + return false; + } + } while (in.expect(',')); + return in.expect('}'); + } + + template <typename Iter> inline bool _parse_number(double& out, input<Iter>& in) { + std::string num_str; + while (1) { + int ch = in.getc(); + if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.' + || ch == 'e' || ch == 'E') { + num_str.push_back(ch); + } else { + in.ungetc(); + break; + } + } + char* endp; + out = strtod(num_str.c_str(), &endp); + return endp == num_str.c_str() + num_str.size(); + } + + template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) { + in.skip_ws(); + int ch = in.getc(); + switch (ch) { +#define IS(ch, text, op) case ch: \ + if (in.match(text) && op) { \ + return true; \ + } else { \ + return false; \ + } + IS('n', "ull", ctx.set_null()); + IS('f', "alse", ctx.set_bool(false)); + IS('t', "rue", ctx.set_bool(true)); +#undef IS + case '"': + return ctx.parse_string(in); + case '[': + return _parse_array(ctx, in); + case '{': + return _parse_object(ctx, in); + default: + if (('0' <= ch && ch <= '9') || ch == '-') { + in.ungetc(); + double f; + if (_parse_number(f, in)) { + ctx.set_number(f); + return true; + } else { + return false; + } + } + break; + } + in.ungetc(); + return false; + } + + class deny_parse_context { + public: + bool set_null() { return false; } + bool set_bool(bool) { return false; } + bool set_number(double) { return false; } + template <typename Iter> bool parse_string(input<Iter>&) { return false; } + bool parse_array_start() { return false; } + template <typename Iter> bool parse_array_item(input<Iter>&, size_t) { + return false; + } + bool parse_object_start() { return false; } + template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) { + return false; + } + }; + + class default_parse_context { + protected: + value* out_; + public: + default_parse_context(value* out) : out_(out) {} + bool set_null() { + *out_ = value(); + return true; + } + bool set_bool(bool b) { + *out_ = value(b); + return true; + } + bool set_number(double f) { + *out_ = value(f); + return true; + } + template<typename Iter> bool parse_string(input<Iter>& in) { + *out_ = value(string_type, false); + return _parse_string(out_->get<std::string>(), in); + } + bool parse_array_start() { + *out_ = value(array_type, false); + return true; + } + template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) { + array& a = out_->get<array>(); + a.push_back(value()); + default_parse_context ctx(&a.back()); + return _parse(ctx, in); + } + bool parse_object_start() { + *out_ = value(object_type, false); + return true; + } + template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) { + object& o = out_->get<object>(); + default_parse_context ctx(&o[key]); + return _parse(ctx, in); + } + private: + default_parse_context(const default_parse_context&); + default_parse_context& operator=(const default_parse_context&); + }; + + class null_parse_context { + public: + struct dummy_str { + void push_back(int) {} + }; + public: + null_parse_context() {} + bool set_null() { return true; } + bool set_bool(bool) { return true; } + bool set_number(double) { return true; } + template <typename Iter> bool parse_string(input<Iter>& in) { + dummy_str s; + return _parse_string(s, in); + } + bool parse_array_start() { return true; } + template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) { + return _parse(*this, in); + } + bool parse_object_start() { return true; } + template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) { + return _parse(*this, in); + } + private: + null_parse_context(const null_parse_context&); + null_parse_context& operator=(const null_parse_context&); + }; + + // obsolete, use the version below + template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) { + std::string err; + pos = parse(out, pos, last, &err); + return err; + } + + template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { + input<Iter> in(first, last); + if (! _parse(ctx, in) && err != NULL) { + char buf[64]; + SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); + *err = buf; + while (1) { + int ch = in.getc(); + if (ch == -1 || ch == '\n') { + break; + } else if (ch >= ' ') { + err->push_back(ch); + } + } + } + return in.cur(); + } + + template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { + default_parse_context ctx(&out); + return _parse(ctx, first, last, err); + } + + inline std::string parse(value& out, std::istream& is) { + std::string err; + parse(out, std::istreambuf_iterator<char>(is.rdbuf()), + std::istreambuf_iterator<char>(), &err); + return err; + } + + template <typename T> struct last_error_t { + static std::string s; + }; + template <typename T> std::string last_error_t<T>::s; + + inline void set_last_error(const std::string& s) { + last_error_t<bool>::s = s; + } + + inline const std::string& get_last_error() { + return last_error_t<bool>::s; + } + + inline bool operator==(const value& x, const value& y) { + if (x.is<null>()) + return y.is<null>(); +#define PICOJSON_CMP(type) \ + if (x.is<type>()) \ + return y.is<type>() && x.get<type>() == y.get<type>() + PICOJSON_CMP(bool); + PICOJSON_CMP(double); + PICOJSON_CMP(std::string); + PICOJSON_CMP(array); + PICOJSON_CMP(object); +#undef PICOJSON_CMP + assert(0); +#ifdef _MSC_VER + __assume(0); +#endif + return false; + } + + inline bool operator!=(const value& x, const value& y) { + return ! (x == y); + } +} + +namespace std { + template<> inline void swap(picojson::value& x, picojson::value& y) + { + x.swap(y); + } +} + +inline std::istream& operator>>(std::istream& is, picojson::value& x) +{ + picojson::set_last_error(std::string()); + std::string err = picojson::parse(x, is); + if (! err.empty()) { + picojson::set_last_error(err); + is.setstate(std::ios::failbit); + } + return is; +} + +inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) +{ + x.serialize(std::ostream_iterator<char>(os)); + return os; +} +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif +#ifdef TEST_PICOJSON +#ifdef _MSC_VER + #pragma warning(disable : 4127) // conditional expression is constant +#endif + +using namespace std; + +static void plan(int num) +{ + printf("1..%d\n", num); +} + +static bool success = true; + +static void ok(bool b, const char* name = "") +{ + static int n = 1; + if (! b) + success = false; + printf("%s %d - %s\n", b ? "ok" : "ng", n++, name); +} + +template <typename T> void is(const T& x, const T& y, const char* name = "") +{ + if (x == y) { + ok(true, name); + } else { + ok(false, name); + } +} + +#include <algorithm> +#include <sstream> +#include <float.h> +#include <limits.h> + +int main(void) +{ + plan(85); + + // constructors +#define TEST(expr, expected) \ + is(picojson::value expr .serialize(), string(expected), "picojson::value" #expr) + + TEST( (true), "true"); + TEST( (false), "false"); + TEST( (42.0), "42"); + TEST( (string("hello")), "\"hello\""); + TEST( ("hello"), "\"hello\""); + TEST( ("hello", 4), "\"hell\""); + + { + double a = 1; + for (int i = 0; i < 1024; i++) { + picojson::value vi(a); + std::stringstream ss; + ss << vi; + picojson::value vo; + ss >> vo; + double b = vo.get<double>(); + if ((i < 53 && a != b) || fabs(a - b) / b > 1e-8) { + printf("ng i=%d a=%.18e b=%.18e\n", i, a, b); + } + a *= 2; + } + } + +#undef TEST + +#define TEST(in, type, cmp, serialize_test) { \ + picojson::value v; \ + const char* s = in; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + ok(err.empty(), in " no error"); \ + ok(v.is<type>(), in " check type"); \ + is<type>(v.get<type>(), cmp, in " correct output"); \ + is(*s, '\0', in " read to eof"); \ + if (serialize_test) { \ + is(v.serialize(), string(in), in " serialize"); \ + } \ + } + TEST("false", bool, false, true); + TEST("true", bool, true, true); + TEST("90.5", double, 90.5, false); + TEST("1.7976931348623157e+308", double, DBL_MAX, false); + TEST("\"hello\"", string, string("hello"), true); + TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"), + true); + TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string, + string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false); + TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false); +#undef TEST + +#define TEST(type, expr) { \ + picojson::value v; \ + const char *s = expr; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + ok(err.empty(), "empty " #type " no error"); \ + ok(v.is<picojson::type>(), "empty " #type " check type"); \ + ok(v.get<picojson::type>().empty(), "check " #type " array size"); \ + } + TEST(array, "[]"); + TEST(object, "{}"); +#undef TEST + + { + picojson::value v; + const char *s = "[1,true,\"hello\"]"; + string err = picojson::parse(v, s, s + strlen(s)); + ok(err.empty(), "array no error"); + ok(v.is<picojson::array>(), "array check type"); + is(v.get<picojson::array>().size(), size_t(3), "check array size"); + ok(v.contains(0), "check contains array[0]"); + ok(v.get(0).is<double>(), "check array[0] type"); + is(v.get(0).get<double>(), 1.0, "check array[0] value"); + ok(v.contains(1), "check contains array[1]"); + ok(v.get(1).is<bool>(), "check array[1] type"); + ok(v.get(1).get<bool>(), "check array[1] value"); + ok(v.contains(2), "check contains array[2]"); + ok(v.get(2).is<string>(), "check array[2] type"); + is(v.get(2).get<string>(), string("hello"), "check array[2] value"); + ok(!v.contains(3), "check not contains array[3]"); + } + + { + picojson::value v; + const char *s = "{ \"a\": true }"; + string err = picojson::parse(v, s, s + strlen(s)); + ok(err.empty(), "object no error"); + ok(v.is<picojson::object>(), "object check type"); + is(v.get<picojson::object>().size(), size_t(1), "check object size"); + ok(v.contains("a"), "check contains property"); + ok(v.get("a").is<bool>(), "check bool property exists"); + is(v.get("a").get<bool>(), true, "check bool property value"); + is(v.serialize(), string("{\"a\":true}"), "serialize object"); + ok(!v.contains("z"), "check not contains property"); + } + +#define TEST(json, msg) do { \ + picojson::value v; \ + const char *s = json; \ + string err = picojson::parse(v, s, s + strlen(s)); \ + is(err, string("syntax error at line " msg), msg); \ + } while (0) + TEST("falsoa", "1 near: oa"); + TEST("{]", "1 near: ]"); + TEST("\n\bbell", "2 near: bell"); + TEST("\"abc\nd\"", "1 near: "); +#undef TEST + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 == v2), "check == operator in deep comparison"); + } + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 != v2), "check != operator for array in deep comparison"); + } + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 != v2), "check != operator for object in deep comparison"); + } + + { + picojson::value v1, v2; + const char *s; + string err; + s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }"; + err = picojson::parse(v1, s, s + strlen(s)); + picojson::object& o = v1.get<picojson::object>(); + o.erase("b"); + picojson::array& a = o["a"].get<picojson::array>(); + picojson::array::iterator i; + i = std::remove(a.begin(), a.end(), picojson::value(std::string("three"))); + a.erase(i, a.end()); + s = "{ \"a\": [1,2], \"d\": 2 }"; + err = picojson::parse(v2, s, s + strlen(s)); + ok((v1 == v2), "check erase()"); + } + + ok(picojson::value(3.0).serialize() == "3", + "integral number should be serialized as a integer"); + + { + const char* s = "{ \"a\": [1,2], \"d\": 2 }"; + picojson::null_parse_context ctx; + string err; + picojson::_parse(ctx, s, s + strlen(s), &err); + ok(err.empty(), "null_parse_context"); + } + + { + picojson::value v1, v2; + v1 = picojson::value(true); + swap(v1, v2); + ok(v1.is<picojson::null>(), "swap (null)"); + ok(v2.get<bool>() == true, "swap (bool)"); + + v1 = picojson::value("a"); + v2 = picojson::value(1.0); + swap(v1, v2); + ok(v1.get<double>() == 1.0, "swap (dobule)"); + ok(v2.get<string>() == "a", "swap (string)"); + + v1 = picojson::value(picojson::object()); + v2 = picojson::value(picojson::array()); + swap(v1, v2); + ok(v1.is<picojson::array>(), "swap (array)"); + ok(v2.is<picojson::object>(), "swap (object)"); + } + + return success ? 0 : 1; +} + +#endif diff --git a/xwalk/common/utils.h b/xwalk/common/utils.h new file mode 100644 index 00000000..ea866c43 --- /dev/null +++ b/xwalk/common/utils.h @@ -0,0 +1,22 @@ +// Copyright (c) 2013 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 COMMON_UTILS_H_ +#define COMMON_UTILS_H_ + +// Put this in the private: declarations for a class to be uncopyable. +#define DISALLOW_COPY(TypeName) \ + TypeName(const TypeName&) + +// Put this in the private: declarations for a class to be unassignable. +#define DISALLOW_ASSIGN(TypeName) \ + void operator=(const TypeName&) + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#endif // COMMON_UTILS_H_ diff --git a/xwalk/common/virtual_fs.cc b/xwalk/common/virtual_fs.cc new file mode 100644 index 00000000..93984a0b --- /dev/null +++ b/xwalk/common/virtual_fs.cc @@ -0,0 +1,317 @@ +// 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 "common/virtual_fs.h" + +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <pkgmgr-info.h> +#include <tzplatform_config.h> + +#include <cassert> +#include <algorithm> +#include <sstream> +#include <string> + +#include "common/extension.h" + +namespace { + +const char kInternalStorage[] = "internal"; +const char kRemovableStorage[] = "removable"; + +const char kStorageTypeInternal[] = "INTERNAL"; +const char kStorageTypeExternal[] = "EXTERNAL"; +const char kStorageStateMounted[] = "MOUNTED"; +const char kStorageStateRemoved[] = "REMOVED"; +const char kStorageStateUnmountable[] = "UNMOUNTABLE"; + +} // namespace + +namespace vfs_const { + +const unsigned kDefaultFileMode = 0755; +const char kLocationCamera[] = "camera"; +const char kLocationMusic[] = "music"; +const char kLocationImages[] = "images"; +const char kLocationVideos[] = "videos"; +const char kLocationDownloads[] = "downloads"; +const char kLocationDocuments[] = "documents"; +const char kLocationRingtones[] = "ringtones"; +const char kLocationWgtPackage[] = "wgt-package"; +const char kLocationWgtPrivate[] = "wgt-private"; +const char kLocationWgtPrivateTmp[] = "wgt-private-tmp"; + +} // namespace vfs_const + +VirtualFS::VirtualFS() { + std::string app_path = GetApplicationPath(); + if (!app_path.empty()) { + AddInternalStorage(vfs_const::kLocationWgtPackage, app_path); + AddInternalStorage(vfs_const::kLocationWgtPrivate, JoinPath(app_path, "private")); + AddInternalStorage(vfs_const::kLocationWgtPrivateTmp, JoinPath(app_path, "tmp")); + } + + AddInternalStorage(vfs_const::kLocationCamera, tzplatform_getenv(TZ_USER_CAMERA)); + AddInternalStorage(vfs_const::kLocationMusic, tzplatform_getenv(TZ_USER_SOUNDS)); + AddInternalStorage(vfs_const::kLocationImages, tzplatform_getenv(TZ_USER_IMAGES)); + AddInternalStorage(vfs_const::kLocationVideos, tzplatform_getenv(TZ_USER_VIDEOS)); + AddInternalStorage(vfs_const::kLocationDownloads, tzplatform_getenv(TZ_USER_DOWNLOADS)); + AddInternalStorage(vfs_const::kLocationDocuments, tzplatform_getenv(TZ_USER_DOCUMENTS)); + AddInternalStorage(vfs_const::kLocationRingtones, + tzplatform_mkpath(TZ_USER_SHARE, "settings/Ringtones")); + storage_changed_cb_ = NULL; + cb_user_data_ = NULL; +} + +VirtualFS::~VirtualFS() { +} + +std::string VirtualFS::JoinPath(const std::string& one, + const std::string& another) { + return one + '/' + another; +} + +bool VirtualFS::MakePath(const std::string& path, int mode) { + // Path should start with '/' and contain at least 1 character after '/'. + if (path.empty() || path[0] != '/' || path.length() < 2) + return false; + + struct stat st; + std::string dir = path; + if (stat(dir.c_str(), &st) == 0) + return true; + + // Add trailing '/' if missing, so we can iterate till the end of the path. + if (dir[dir.size() - 1] != '/') + dir += '/'; + + for (std::string::iterator iter = dir.begin(); iter != dir.end();) { + std::string::iterator cur_iter = std::find(iter, dir.end(), '/'); + + // If '/' is found at the beginning of the string, iterate to the next '/'. + if (cur_iter == iter) { + ++iter; + cur_iter = std::find(iter, dir.end(), '/'); + } + + std::string new_path = std::string(dir.begin(), cur_iter); + + // If path doesn't exist, try to create one and continue iteration. + // In case of error, stop iteration and return. + if (stat(new_path.c_str(), &st) != 0) { + if (mkdir(new_path.c_str(), mode) != 0 && errno != EEXIST ) + return false; + // If path exists and it is not a directory, stop iteration and return. + } else if (!S_ISDIR(st.st_mode)) { + return false; + } + + // Advance iterator and create next parent folder. + iter = cur_iter; + if (cur_iter != dir.end()) + ++iter; + } + return true; +} + +int VirtualFS::GetDirEntryCount(const char* path) { + int count = 0; + DIR* dir = opendir(path); + if (!dir) + return count; + + struct dirent entry; + struct dirent *result; + int ret = readdir_r(dir, &entry, &result); + + for (; ret == 0 && result != NULL; ret = readdir_r(dir, &entry, &result)) { + if (entry.d_type == DT_REG || entry.d_type == DT_DIR) + count++; + } + + closedir(dir); + return count; +} + +std::string VirtualFS::GetAppId(const std::string& package_id) { + char* appid = NULL; + pkgmgrinfo_pkginfo_h pkginfo_handle; + int ret = pkgmgrinfo_pkginfo_get_pkginfo(package_id.c_str(), &pkginfo_handle); + if (ret != PMINFO_R_OK) + return std::string(); + ret = pkgmgrinfo_pkginfo_get_mainappid(pkginfo_handle, &appid); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle); + return std::string(); + } + + std::string retval(appid); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle); + return retval; +} + +std::string VirtualFS::GetExecPath(const std::string& app_id) { + char* exec_path = NULL; + pkgmgrinfo_appinfo_h appinfo_handle; + int ret = pkgmgrinfo_appinfo_get_appinfo(app_id.c_str(), &appinfo_handle); + if (ret != PMINFO_R_OK) + return std::string(); + ret = pkgmgrinfo_appinfo_get_exec(appinfo_handle, &exec_path); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_appinfo_destroy_appinfo(appinfo_handle); + return std::string(); + } + + std::string retval(exec_path); + pkgmgrinfo_appinfo_destroy_appinfo(appinfo_handle); + return retval; +} + +bool VirtualFS::GetStorageByLabel(const std::string& label, Storage& storage) { + storage_foreach_device_supported(OnStorageDeviceSupported, this); + Storages::const_iterator it = storages_.find(label); + + if (it == storages_.end()) { + return false; + } + storage = it->second; + return true; +} + +Storages::iterator VirtualFS::begin() { + storage_foreach_device_supported(OnStorageDeviceSupported, this); + return storages_.begin(); +} + +Storages::const_iterator VirtualFS::end() const { + return storages_.end(); +} + +std::string VirtualFS::GetApplicationPath() { + std::string id_str = common::Extension::GetRuntimeVariable("app_id", 64); + std::string pkg_id = id_str.substr(1, id_str.rfind('"') - 1); + if (pkg_id.empty()) + return std::string(); + std::string app_id = GetAppId(pkg_id); + if (app_id.empty()) + return std::string(); + std::string exec_path = GetExecPath(app_id); + if (exec_path.empty()) + return std::string(); + + size_t index = exec_path.find(pkg_id); + if (index != std::string::npos) + return exec_path.substr(0, index + pkg_id.length()); + return std::string(); +} + +std::string VirtualFS::GetRealPath(const std::string& fullPath) const { + std::size_t pos = fullPath.find_first_of('/'); + Storages::const_iterator it = storages_.find(fullPath.substr(0, pos)); + + if (it == storages_.end()) + return std::string(); + + if (pos != std::string::npos) + return it->second.GetFullPath() + fullPath.substr(pos); + + return it->second.GetFullPath(); +} + +void VirtualFS::AddInternalStorage( + const std::string& label, const std::string& path) { + if (MakePath(path, vfs_const::kDefaultFileMode)) + storages_.insert(StorageLabelPair(label, + Storage(-1, + Storage::STORAGE_TYPE_INTERNAL, + Storage::STORAGE_STATE_MOUNTED, + path))); +} + +void VirtualFS::AddStorage(int id, + storage_type_e type, + storage_state_e state, + const std::string& path) { + std::string label; + if (type == STORAGE_TYPE_INTERNAL) + label = kInternalStorage + std::to_string(id); + else if (type == STORAGE_TYPE_EXTERNAL) + label = kRemovableStorage + std::to_string(id); + + storages_.insert(StorageLabelPair(label, + Storage(id, + type, + state, + path))); + if (std::find(watched_storages_.begin(), + watched_storages_.end(), id) != watched_storages_.end()) { + watched_storages_.push_back(id); + storage_set_state_changed_cb(id, OnStorageStateChanged, this); + } +} + +void VirtualFS::SetOnStorageChangedCb(CallBackFunctionPtr cb, void* user_data) { + storage_changed_cb_ = cb; + cb_user_data_ = user_data; +} + +void VirtualFS::NotifyStorageStateChanged(int id, storage_state_e state) { + for (Storages::iterator it = storages_.begin(); it != storages_.end(); ++it) { + if (it->second.GetId() == id) { + it->second.SetState(state); + if (storage_changed_cb_) { + storage_changed_cb_(it->first, it->second, cb_user_data_); + } + break; + } + } +} + +bool VirtualFS::OnStorageDeviceSupported( + int id, storage_type_e type, storage_state_e state, + const char* path, void* user_data) { + reinterpret_cast<VirtualFS*>(user_data)->AddStorage( + id, type, state, path); + return true; +} + +void VirtualFS::OnStorageStateChanged( + int id, storage_state_e state, void* user_data) { + reinterpret_cast<VirtualFS*>(user_data)->NotifyStorageStateChanged( + id, state); +} + +/* + * Storage Class + */ + +Storage::Storage( + int id, int type, int state, const std::string& fullpath) + : id_(id), + type_(type), + state_(state), + full_path_(fullpath) { } + +std::string Storage::GetType() const { + return (type_ == Storage::STORAGE_TYPE_INTERNAL) ? kStorageTypeInternal : + kStorageTypeExternal; +} + +std::string Storage::GetState() const { + switch (state_) { + case Storage::STORAGE_STATE_MOUNTED: + case Storage::STORAGE_STATE_MOUNTED_READONLY: + return kStorageStateMounted; + case Storage::STORAGE_STATE_REMOVED: + return kStorageStateRemoved; + case Storage::STORAGE_STATE_UNMOUNTABLE: + return kStorageStateUnmountable; + default: + assert(!"Not reached"); + } + return std::string(); +} diff --git a/xwalk/common/virtual_fs.h b/xwalk/common/virtual_fs.h new file mode 100644 index 00000000..94a988f1 --- /dev/null +++ b/xwalk/common/virtual_fs.h @@ -0,0 +1,130 @@ +// 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 COMMON_VIRTUAL_FS_H_ +#define COMMON_VIRTUAL_FS_H_ + +#include <appfw/app_storage.h> + +#include <map> +#include <set> +#include <string> +#include <utility> +#include <vector> + +namespace vfs_const { + +extern const unsigned kDefaultFileMode; +extern const char kLocationCamera[]; +extern const char kLocationMusic[]; +extern const char kLocationImages[]; +extern const char kLocationVideos[]; +extern const char kLocationDownloads[]; +extern const char kLocationDocuments[]; +extern const char kLocationRingtones[]; +extern const char kLocationWgtPackage[]; +extern const char kLocationWgtPrivate[]; +extern const char kLocationWgtPrivateTmp[]; + +} // namespace vfs_const + +class Storage { + public: + /* Mapped to storage_type_e */ + enum StorageType { + STORAGE_TYPE_INTERNAL, STORAGE_TYPE_EXTERNAL, + }; + + /* Mapped to storage_state_e */ + enum StorageState { + STORAGE_STATE_UNMOUNTABLE = -2, + STORAGE_STATE_REMOVED = -1, + STORAGE_STATE_MOUNTED = 0, + STORAGE_STATE_MOUNTED_READONLY = 1, + }; + + Storage(int id = 0, int type = 0, int state = 0, + const std::string& fullpath = ""); + + std::string GetType() const; + std::string GetState() const; + int GetId() const { return id_; } + const std::string& GetFullPath() const { return full_path_; } + void SetState(int state) { state_ = state; } + + private: + int id_; + int type_; + int state_; + std::string full_path_; +}; + +typedef std::map<std::string, Storage> Storages; +typedef void(*CallBackFunctionPtr)(const std::string&, Storage, void*); + +/** + * The VirtualFS class provide an abstraction of the TIZEN virtual filesystem. + * It manages mounted storages and virtual roots, creating missing directories + * if needed. + * Convenient functions are also provided for working with paths (real or + * virtual). + */ +class VirtualFS { + public: + VirtualFS(); + ~VirtualFS(); + /** + * Resolve the given fullpath within the virtual filesystem to an absolute + * path within the real filesystem. + * @param fullPath: fully-qualified path of the form: <root name>/<path> + * where <rootname> is the name of the virtual root and <path> is the path + * to the file or directory relative to that root. + * @return full Linux path. + */ + std::string GetRealPath(const std::string& fullPath) const; + bool GetStorageByLabel(const std::string& label, Storage& storage); + Storages::iterator begin(); + Storages::const_iterator end() const; + void SetOnStorageChangedCb(CallBackFunctionPtr cb, void* user_data); + + /** + * Concatenate two paths. + * @param one: base path. + * @param another: path within 'one'. + * @return new path. + */ + static std::string JoinPath(const std::string& one, + const std::string& another); + /** + * Create full path and parent directories when needed. + * Similar to "mkdir -p". + * @param path: the path to be created. + * @param mode: the unix access mode applied to the new directories. + * @return true if success. + */ + static bool MakePath(const std::string& path, int mode); + static int GetDirEntryCount(const char* path); + static std::string GetAppId(const std::string& package_id); + static std::string GetExecPath(const std::string& app_id); + static std::string GetApplicationPath(); + + private: + void AddInternalStorage(const std::string& label, const std::string& path); + void AddStorage(int storage, storage_type_e type, storage_state_e state, + const std::string& path); + void NotifyStorageStateChanged(int id, storage_state_e state); + static bool OnStorageDeviceSupported(int id, storage_type_e type, + storage_state_e state, const char* path, void* user_data); + static void OnStorageStateChanged(int id, storage_state_e state, + void* user_data); + + CallBackFunctionPtr storage_changed_cb_; + void* cb_user_data_; + + typedef std::pair<std::string, Storage> StorageLabelPair; + Storages storages_; + std::vector<int> watched_storages_; +}; + +#endif // COMMON_VIRTUAL_FS_H_ diff --git a/xwalk/generate_api.py b/xwalk/generate_api.py new file mode 100755 index 00000000..cef97b7a --- /dev/null +++ b/xwalk/generate_api.py @@ -0,0 +1,19 @@ +# Copyright (c) 2013 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. + +import sys + +TEMPLATE = """\ +extern const char %s[]; +const char %s[] = { %s, 0 }; +""" + +js_code = sys.argv[1] +lines = file(js_code).read() +c_code = ', '.join(str(ord(c)) for c in lines) + +symbol_name = sys.argv[2] +output = open(sys.argv[3], "w") +output.write(TEMPLATE % (symbol_name, symbol_name, c_code)) +output.close() diff --git a/xwalk/vehicle.cc b/xwalk/vehicle.cc new file mode 100644 index 00000000..3eda44ef --- /dev/null +++ b/xwalk/vehicle.cc @@ -0,0 +1,711 @@ +// 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.h" + +#include <abstractpropertytype.h> +#include <debugout.h> +#include <gio/gio.h> +#include <glib.h> +#include <listplusplus.h> +#include <superptr.hpp> + +#include <algorithm> +#include <map> +#include <memory> + +#include "common/extension.h" +#include "common/picojson.h" + +common::Instance* Vehicle::CallbackInfo::instance = nullptr; + +namespace { +const char* amb_service = "org.automotive.message.broker"; +const char* prop_iface = "org.freedesktop.DBus.Properties"; + +const char* vehicle_error_permission_denied = "permission_denied"; +const char* vehicle_error_invalid_operation = "invalid_operation"; +const char* vehicle_error_timeout = "timeout"; +const char* vehicle_error_invalid_zone = "invalid_zone"; +const char* vehicle_error_unknown = "unknown"; + +picojson::value::array AmbZoneToW3C(const std::vector<int>& amb_zones); +picojson::value::array AmbZoneToW3C(int amb_zone); + +template<typename T> unique_ptr<T> make_unique(T* t) { + return unique_ptr<T>(t); +} + +void PostReply(Vehicle::CallbackInfo* cb_obj, picojson::value object) { + DebugOut() << "Posting reply" << endl; + picojson::object msg; + + msg["method"] = picojson::value(cb_obj->method); + msg["asyncCallId"] = picojson::value(cb_obj->callback_id); + msg["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, const 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)); + } else if (type == "s") { + v = picojson::value(g_variant_get_string(value, nullptr)); + } + + return v; +} + +GVariant* GetBasic(picojson::value value, const std::string& type) { + GVariant* v = nullptr; + + if (type == "i") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "d") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "q") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "n") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "y") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "u") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "x") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "t") { + v = g_variant_new(type.c_str(), value.get<double>()); + } else if (type == "b") { + v = g_variant_new(type.c_str(), value.get<bool>()); + } else if (type == "s") { + v = g_variant_new(type.c_str(), value.get<std::string>().c_str()); + } + + return v; +} + +void AsyncGetCallback(GObject* source, GAsyncResult* res, gpointer user_data) { + debugOut("GetAll() method call completed"); + + Vehicle::CallbackInfo *cb_obj = + static_cast<Vehicle::CallbackInfo*>(user_data); + + auto cb_obj_ptr = make_unique(cb_obj); + + if (!cb_obj_ptr) { + debugOut("invalid cb object"); + return; + } + + GError* error = nullptr; + + auto property_map = amb::make_super( + g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error)); + + auto error_ptr = amb::make_super(error); + + if (error_ptr) { + DebugOut() << "failed to call GetAll on interface: " + << error_ptr->message << endl; + PostError(cb_obj_ptr.get(), "unknown"); + return; + } + + GVariantIter* iter; + gchar* key; + GVariant* value; + + g_variant_get(property_map.get(), "(a{sv})", &iter); + + auto iter_ptr = amb::make_super(iter); + + picojson::value::object object; + + while (g_variant_iter_next(iter_ptr.get(), "{sv}", &key, &value)) { + auto key_ptr = amb::make_super(key); + auto value_ptr = amb::make_super(value); + + std::string temp_key = key_ptr.get(); + + std::transform(temp_key.begin(), temp_key.begin() + 1, + temp_key.begin(), ::tolower); + + object[temp_key] = GetBasic(value_ptr.get()); + + if (temp_key == "zone") { + object[temp_key] = + picojson::value(AmbZoneToW3C(object[temp_key].get<double>())); + } + } + + PostReply(cb_obj_ptr.get(), picojson::value(object)); +} + +picojson::value::array AmbZoneToW3C(int amb_zone) { + picojson::value::array z; + + if (amb_zone & Zone::Left) { + z.push_back(picojson::value("Left")); + } + if (amb_zone & Zone::Right) { + z.push_back(picojson::value("Right")); + } + if (amb_zone & Zone::Front) { + z.push_back(picojson::value("Front")); + } + if (amb_zone & Zone::Middle) { + z.push_back(picojson::value("Middle")); + } + if (amb_zone & Zone::Center) { + z.push_back(picojson::value("Center")); + } + if (amb_zone & Zone::Rear) { + z.push_back(picojson::value("Rear")); + } + + return z; +} + +picojson::value::array AmbZoneToW3C(const std::vector<int>& amb_zones) { + picojson::value::array zones; + + for (auto i : amb_zones) { + zones.push_back(picojson::value(AmbZoneToW3C(i))); + } + + return zones; +} + +static void SignalCallback(GDBusConnection* connection, + const gchar*, + const gchar* object_path, + const gchar*, + const gchar*, + GVariant* parameters, + gpointer user_data) { + DebugOut() << "Got signal" << endl; + std::vector<ObjectZone*> amb_objects_ = + *(static_cast<std::vector<ObjectZone*>*>(user_data)); + + GVariant* value_array; + GVariant* iface_name; + GVariant* invalidated; + + g_variant_get(parameters, + "(&s@a{sv}^a&s)", + &iface_name, + &value_array, + &invalidated); + + GVariantIter iter; + + g_variant_iter_init(&iter, value_array); + + ObjectZone* object = nullptr; + + for (auto i : amb_objects_) { + if (i->object_path == object_path) { + object = i; + } + } + + if (!object) { + DebugOut(DebugOut::Error) << "received signal for which " + << "we have no corresponding amb object" << endl; + return; + } + + char* key; + GVariant* value; + + while (g_variant_iter_next(&iter, "{sv}", &key, &value)) { + auto key_ptr = amb::make_super(key); + auto value_ptr = amb::make_super(value); + + std::string tempkey = key_ptr.get(); + + std::transform(tempkey.begin(), tempkey.begin() + 1, tempkey.begin(), + ::tolower); + + object->value[tempkey] = GetBasic(value_ptr.get()); + + if (tempkey == "zone") { + object->value[tempkey] = + picojson::value(AmbZoneToW3C(object->value[tempkey].get<double>())); + } + } + + object->value["interfaceName"] = picojson::value(object->name); + + Vehicle::CallbackInfo call; + call.method = "subscribe"; + call.callback_id = -1; + + PostReply(&call, picojson::value(object->value)); +} + +} // namespace + +Vehicle::Vehicle(common::Instance* instance) + : main_loop_(g_main_loop_new(0, FALSE)), + thread_(Vehicle::SetupMainloop, this), + instance_(instance) { + CallbackInfo::instance = instance_; + thread_.detach(); +} + +Vehicle::~Vehicle() { + g_main_loop_quit(main_loop_); + g_main_loop_unref(main_loop_); + + for (auto i : amb_objects_) { + delete i; + } +} + +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 find_error; + std::string obj_pstr = FindProperty(property, zone, find_error); + + if (obj_pstr.empty()) { + debugOut("could not find property " + property); + PostError(data, find_error); + return; + } + + GError* error = nullptr; + + auto properties_proxy = amb::make_super( + g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, NULL, + amb_service, + obj_pstr.c_str(), + prop_iface, + NULL, + &error)); + + auto error_ptr = amb::make_super(error); + + if (error_ptr) { + DebugOut(DebugOut::Error) << "failed to get properties proxy: " << error->message << endl; + return; + } + + std::string interfaceName = "org.automotive." + property; + + g_dbus_proxy_call(properties_proxy.get(), + "GetAll", + g_variant_new("(s)", interfaceName.c_str()), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, + AsyncGetCallback, data); +} + +void Vehicle::GetZones(const std::string& object_name, double ret_id) { + auto manager_proxy = amb::make_super(GetAutomotiveManager()); + + if (!manager_proxy) { + return; + } + + GError* error(nullptr); + + auto zones_variant = amb::make_super( + g_dbus_proxy_call_sync(manager_proxy.get(), + "ZonesForObjectName", + g_variant_new("(s)", + object_name.c_str()), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error)); + + auto error_ptr = amb::make_super(error); + + if (error_ptr) { + DebugOut() << "error calling ZonesForObjectName: " + << error_ptr->message << endl; + return; + } + + if (!zones_variant) { + DebugOut() << "Invalid response from ZonesForObjectName " << endl; + return; + } + + GVariantIter* iter(nullptr); + + g_variant_get(zones_variant.get(), "(ai)", &iter); + + if (!iter) { + DebugOut() << "No zones for object " << object_name << endl; + return; + } + + auto iter_ptr = amb::make_super(iter); + + std::vector<int> zones_array; + + GVariant* value(nullptr); + + while ((value = g_variant_iter_next_value(iter_ptr.get()))) { + auto value_ptr = amb::make_super(value); + int v = 0; + + g_variant_get(value_ptr.get(), "(i)", &v); + zones_array.push_back(v); + } + + picojson::value::array w3c_zones = AmbZoneToW3C(zones_array); + + CallbackInfo* data = new CallbackInfo; + + data->callback_id = ret_id; + data->method = "zones"; + data->instance = instance_; + + PostReply(data, picojson::value(w3c_zones)); +} + +std::string Vehicle::FindProperty(const std::string& object_name, int zone, std::string& error_str) { + GDBusProxy* manager_proxy = GetAutomotiveManager(); + + if (!manager_proxy) { + return ""; + } + + GError* error(nullptr); + + auto object_path_variant = amb::make_super( + g_dbus_proxy_call_sync(manager_proxy, + "FindObjectForZone", + g_variant_new("(si)", + object_name.c_str(), + zone), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error)); + + auto error_ptr = amb::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 = amb::make_super(obj_path); + + DebugOut() << "FindObjectForZone() returned object path: " + << obj_path_ptr.get() << endl; + + return obj_path; +} + +GDBusProxy* Vehicle::GetAutomotiveManager() { + if (manager_proxy_) + return manager_proxy_.get(); + + GError* error = nullptr; + manager_proxy_ = amb::make_super(g_dbus_proxy_new_sync(dbus_connection_.get(), + G_DBUS_PROXY_FLAGS_NONE, NULL, + amb_service, + "/", + "org.automotive.Manager", + NULL, + &error)); + + auto error_ptr = amb::make_super(error); + + if (error_ptr) { + DebugOut() << "error calling GetAutomotiveManager: " + << error_ptr->message << endl; + } + + return manager_proxy_.get(); +} + +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_); +} + + +void Vehicle::Subscribe(const std::string& object_name, Zone::Type zone) { + std::string find_error; + std::string object_path = FindProperty(object_name, zone, find_error); + + if (object_path.empty()) { + DebugOut() << "Error FindProperty failed for " << object_name; + return; + } + + bool already_subscribed = false; + + for (auto i : amb_objects_) { + if (i->object_path == object_path) { + already_subscribed = true; + break; + } + } + + if (!already_subscribed) { + GError* proxy_error = nullptr; + + auto properties_proxy = + amb::make_super(g_dbus_proxy_new_sync(dbus_connection_.get(), + G_DBUS_PROXY_FLAGS_NONE, + NULL, + amb_service, + object_path.c_str(), + prop_iface, + NULL, + &proxy_error)); + + auto proxy_error_ptr = amb::make_super(proxy_error); + + if (proxy_error_ptr) { + DebugOut() << "error creating properties proxy: " + << proxy_error_ptr->message << endl; + } + + std::string interface_name = "org.automotive." + object_name; + + GError* get_all_error = nullptr; + + GVariant* property_map = + g_dbus_proxy_call_sync(properties_proxy.get(), + "GetAll", + g_variant_new("(s)", interface_name.c_str()), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, + &get_all_error); + + auto get_all_error_ptr = amb::make_super(get_all_error); + + if (get_all_error_ptr) { + DebugOut(DebugOut::Error) << "failed to call GetAll on interface " + << interface_name << " " + << get_all_error_ptr->message << endl; + return; + } + + GVariantIter* iter; + + g_variant_get(property_map, "(a{sv})", &iter); + + auto iter_ptr = amb::make_super(iter); + + char* key; + GVariant* value; + + ObjectZone* object = new ObjectZone(object_name, zone, object_path); + + while (g_variant_iter_next(iter_ptr.get(), "{sv}", &key, &value)) { + auto key_ptr = amb::make_super(key); + auto value_ptr = amb::make_super(value); + + std::string tempkey = key_ptr.get(); + + std::transform(tempkey.begin(), tempkey.begin() + 1, tempkey.begin(), + ::tolower); + + object->value[tempkey] = GetBasic(value_ptr.get()); + } + + object->handle = + g_dbus_connection_signal_subscribe(dbus_connection_.get(), + amb_service, + prop_iface, + "PropertiesChanged", + object_path.c_str(), NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + SignalCallback, &amb_objects_, + NULL); + + amb_objects_.push_back(object); + } else { + DebugOut() << "Already subscribed to " << object_name << endl; + } +} + + +void Vehicle::Unsubscribe(const std::string& property, Zone::Type zone) { + std::vector<ObjectZone*> to_clean; + + for (auto obj : amb_objects_) { + if (obj->name == property && obj->zone == zone) { + g_dbus_connection_signal_unsubscribe(dbus_connection_.get(), + obj->handle); + to_clean.push_back(obj); + } + } + + for (auto obj : to_clean) { + removeOne(&amb_objects_, obj); + delete obj; + } +} + + +void Vehicle::Set(const std::string &object_name, picojson::object value, + Zone::Type zone, double ret_id) +{ + std::string find_error; + std::string object_path = FindProperty(object_name, zone, find_error); + + Vehicle::CallbackInfo callback; + callback.callback_id = ret_id; + callback.method = "set"; + callback.instance = instance_; + + if (object_path.empty() || !find_error.empty()) { + DebugOut(DebugOut::Error) << "Object not found. Check object Name and zone." + << object_name << std::endl; + PostError(&callback, find_error); + return; + } + + GError* proxy_error = nullptr; + + auto properties_proxy = + amb::make_super(g_dbus_proxy_new_sync(dbus_connection_.get(), + G_DBUS_PROXY_FLAGS_NONE, + NULL, + amb_service, + object_path.c_str(), + prop_iface, + NULL, + &proxy_error)); + + auto proxy_error_ptr = amb::make_super(proxy_error); + + if (proxy_error_ptr) { + DebugOut(DebugOut::Error) << "Error creating property proxy for " << object_path << std::endl; + return; + } + + std::string interface_name = "org.automotive." + object_name; + + for (auto itr : value) { + GError* err = nullptr; + std::string attribute = itr.first; + + std::transform(attribute.begin(), attribute.begin()+1, attribute.begin(), ::toupper); + + auto var_value = + amb::make_super(g_dbus_proxy_call_sync(properties_proxy.get(), + "Get", + g_variant_new("(ss)", + interface_name.c_str(), + attribute.c_str()), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err)); + auto err_ptr = amb::make_super(err); + if (err_ptr || !var_value) { + DebugOut(DebugOut::Error) << "Error getting initial property signature type: " << + err_ptr->message << endl; + PostError(&callback, vehicle_error_unknown); + return; + } + + GVariant* get_value = nullptr; + g_variant_get(var_value.get(), "(v)", &get_value); + + auto get_value_ptr = amb::make_super(get_value); + + if (!get_value_ptr) { + DebugOut(DebugOut::Error) << "Error getting variant value." << endl; + PostError(&callback, vehicle_error_unknown); + return; + } + + GVariant* v = GetBasic(itr.second, g_variant_get_type_string(get_value_ptr.get())); + + if (!v) { + DebugOut(DebugOut::Error) << "Error converting value to GVariant" << endl; + PostError(&callback, vehicle_error_unknown); + } + + GError* set_error = nullptr; + + g_dbus_proxy_call_sync(properties_proxy.get(), "Set", + g_variant_new("(ssv)", + interface_name.c_str(), + attribute.c_str(), + v), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &set_error); + + auto set_error_ptr = amb::make_super(set_error); + + if (set_error_ptr) { + DebugOut(DebugOut::Error) << "error setting property:" << set_error_ptr->message << endl; + + if(set_error_ptr->code == G_IO_ERROR_PERMISSION_DENIED || std::string(g_dbus_error_get_remote_error(set_error_ptr.get())) == "org.freedesktop.DBus.Error.AccessDenied") + { + DebugOut(DebugOut::Error) << "permission denied" << endl; + PostError(&callback, vehicle_error_permission_denied); + } + PostError(&callback, vehicle_error_unknown); + return; + } + } + + PostReply(&callback, picojson::value()); +} diff --git a/xwalk/vehicle.h b/xwalk/vehicle.h new file mode 100644 index 00000000..63eebd43 --- /dev/null +++ b/xwalk/vehicle.h @@ -0,0 +1,89 @@ +// 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 <superptr.hpp> + +#include <string> +#include <thread> // NOLINT +#include <vector> + +#include "common/picojson.h" + +namespace common { + +class Instance; + +} // namespace common + +struct ObjectZone { + ObjectZone():zone(0) {} + + ObjectZone(const std::string& o, int z, const std::string& op) + : name(o), zone(z), object_path(op) {} + + ObjectZone(const ObjectZone& other) + : name(other.name), zone(other.zone), object_path(other.object_path) {} + + std::string name; + int zone; + uint handle; + + std::string object_path; + + bool operator ==(const ObjectZone& other) const { + return object_path == other.object_path; + } + + picojson::object value; +}; + +struct ObjectZoneCompare { + bool operator() (const ObjectZone& lhs, const ObjectZone& rhs) { + return (lhs.name == rhs.name && lhs.zone < rhs.zone) || + (lhs.name < rhs.name); + } +}; + +typedef std::function<void (picojson::object)> GetReply; +typedef std::function<void (std::string)> ErrorReply; + +class Vehicle { + public: + struct CallbackInfo { + std::string method; + static common::Instance* instance; + double callback_id; + }; + + explicit Vehicle(common::Instance* i); + ~Vehicle(); + + void Get(const std::string& property, Zone::Type zone, double ret_id); + void GetZones(const std::string& property, double ret_id); + void Subscribe(const std::string& property, Zone::Type zone); + void Unsubscribe(const std::string& property, Zone::Type zone); + void Set(const std::string& property, picojson::object value, Zone::Type zone, double ret_id); + + private: + std::string FindProperty(const std::string& object_name, int zone, string &error_str); + GDBusProxy* GetAutomotiveManager(); + + static void SetupMainloop(void* data); + GMainLoop* main_loop_; + std::thread thread_; + common::Instance* instance_; + + std::vector<ObjectZone*> amb_objects_; + + amb::super_ptr<GDBusProxy> manager_proxy_; + amb::super_ptr<GDBusConnection> dbus_connection_; +}; + +#endif // VEHICLE_VEHICLE_H_ diff --git a/xwalk/vehicle.html b/xwalk/vehicle.html new file mode 100644 index 00000000..b4eecf7c --- /dev/null +++ b/xwalk/vehicle.html @@ -0,0 +1,61 @@ +<html> +<h1>Hello,Vehicle API!</h1> + +<body> +<pre id="console"></pre> +<script> + +function debug(stuff) { + console.log(stuff); +} + +vehicle = navigator.vehicle; + +debug('vehicle.vehicleSpeed ' + vehicle.vehicleSpeed); + +var zone = new Zone; + +console.log('Driver zone: ' + zone.driver.value); + +var zone1 = new Zone(["Front", "Left"]); +var zone2 = new Zone(["Left", "Front"]); +var zone3 = new Zone(["Front", "Right"]); +var zone4 = new Zone([]); + +debug("zone1 == zone2 ? " + zone1.equals(zone2)); +debug("zone1 == zone3 ? " + zone1.equals(zone3)); +debug("zone1 == zone1 ? " + zone1.equals(zone1)); +debug("zone1 == empty zone ? " + zone1.equals(zone4)); + +vehicle.vehicleSpeed.get().then(function(vehicleSpeed) { + try { + console.log("vehicle speed " + JSON.stringify(vehicleSpeed)); + debug("Vehicle speed: " + vehicleSpeed.speed); + } catch(error) { + console.log("error " + error.message); + } +}, +function(error) { + debug("There was an error"); +}); + +//test subscribe: +var subReplies = 0; +var handle = vehicle.vehicleSpeed.subscribe(function(data) { + console.log("got subscribe callback"); + debug("Vehicle speed changed: " + data.speed); + subReplies++; + + if (subReplies === 5) { + debug("unsubscribing"); + vehicle.vehicleSpeed.unsubscribe(handle); + } +}); + +//test errors: +vehicle.vehicleSpeed.get("invalidzone").then(function() { }, + function(error) { debug("Invalid zone: " + error.message); }); + +</script> +</body> +</html> diff --git a/xwalk/vehicle_api.cc b/xwalk/vehicle_api.cc new file mode 100644 index 00000000..aaeb6a06 --- /dev/null +++ b/xwalk/vehicle_api.cc @@ -0,0 +1,2 @@ +extern const char kSource_vehicle_api[]; +const char kSource_vehicle_api[] = { 47, 47, 32, 67, 111, 112, 121, 114, 105, 103, 104, 116, 32, 40, 99, 41, 32, 50, 48, 49, 52, 32, 73, 110, 116, 101, 108, 32, 67, 111, 114, 112, 111, 114, 97, 116, 105, 111, 110, 46, 32, 65, 108, 108, 32, 114, 105, 103, 104, 116, 115, 32, 114, 101, 115, 101, 114, 118, 101, 100, 46, 10, 47, 47, 32, 85, 115, 101, 32, 111, 102, 32, 116, 104, 105, 115, 32, 115, 111, 117, 114, 99, 101, 32, 99, 111, 100, 101, 32, 105, 115, 32, 103, 111, 118, 101, 114, 110, 101, 100, 32, 98, 121, 32, 97, 32, 66, 83, 68, 45, 115, 116, 121, 108, 101, 32, 108, 105, 99, 101, 110, 115, 101, 32, 116, 104, 97, 116, 32, 99, 97, 110, 32, 98, 101, 10, 47, 47, 32, 102, 111, 117, 110, 100, 32, 105, 110, 32, 116, 104, 101, 32, 76, 73, 67, 69, 78, 83, 69, 32, 102, 105, 108, 101, 46, 10, 10, 118, 97, 114, 32, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 32, 61, 32, 48, 59, 10, 118, 97, 114, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 32, 61, 32, 123, 125, 59, 10, 10, 118, 97, 114, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 32, 61, 32, 91, 93, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 118, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 67, 111, 109, 109, 111, 110, 67, 111, 110, 116, 114, 117, 99, 116, 111, 114, 40, 111, 98, 106, 44, 32, 97, 116, 116, 110, 97, 109, 101, 41, 32, 123, 10, 32, 32, 111, 98, 106, 46, 97, 116, 116, 114, 105, 98, 117, 116, 101, 78, 97, 109, 101, 32, 61, 32, 97, 116, 116, 110, 97, 109, 101, 59, 10, 10, 32, 32, 118, 97, 114, 32, 109, 115, 103, 32, 61, 32, 123, 125, 59, 10, 32, 32, 109, 115, 103, 91, 39, 109, 101, 116, 104, 111, 100, 39, 93, 32, 61, 32, 39, 122, 111, 110, 101, 115, 39, 59, 10, 32, 32, 109, 115, 103, 91, 39, 110, 97, 109, 101, 39, 93, 32, 61, 32, 111, 98, 106, 46, 97, 116, 116, 114, 105, 98, 117, 116, 101, 78, 97, 109, 101, 59, 10, 10, 32, 32, 111, 98, 106, 46, 95, 122, 111, 110, 101, 115, 32, 61, 32, 110, 101, 119, 32, 90, 111, 110, 101, 59, 10, 10, 32, 32, 118, 97, 114, 32, 99, 97, 108, 108, 32, 61, 32, 110, 101, 119, 32, 65, 115, 121, 110, 99, 67, 97, 108, 108, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, 100, 97, 116, 97, 41, 32, 123, 10, 32, 32, 32, 32, 111, 98, 106, 46, 95, 122, 111, 110, 101, 115, 32, 61, 32, 100, 97, 116, 97, 59, 10, 32, 32, 125, 41, 59, 10, 10, 32, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 91, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 93, 32, 61, 32, 99, 97, 108, 108, 59, 10, 32, 32, 109, 115, 103, 46, 97, 115, 121, 110, 99, 67, 97, 108, 108, 73, 100, 32, 61, 32, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 59, 10, 32, 32, 43, 43, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 59, 10, 10, 32, 32, 101, 120, 116, 101, 110, 115, 105, 111, 110, 46, 112, 111, 115, 116, 77, 101, 115, 115, 97, 103, 101, 40, 74, 83, 79, 78, 46, 115, 116, 114, 105, 110, 103, 105, 102, 121, 40, 109, 115, 103, 41, 41, 59, 10, 10, 32, 32, 79, 98, 106, 101, 99, 116, 46, 100, 101, 102, 105, 110, 101, 80, 114, 111, 112, 101, 114, 116, 121, 40, 111, 98, 106, 44, 32, 39, 122, 111, 110, 101, 115, 39, 44, 32, 123, 32, 103, 101, 116, 58, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 41, 32, 123, 32, 114, 101, 116, 117, 114, 110, 32, 111, 98, 106, 46, 95, 122, 111, 110, 101, 115, 32, 125, 32, 125, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 86, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 40, 97, 116, 116, 110, 97, 109, 101, 41, 32, 123, 10, 32, 32, 118, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 67, 111, 109, 109, 111, 110, 67, 111, 110, 116, 114, 117, 99, 116, 111, 114, 40, 116, 104, 105, 115, 44, 32, 97, 116, 116, 110, 97, 109, 101, 41, 59, 10, 125, 10, 10, 86, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 46, 103, 101, 116, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 122, 111, 110, 101, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 109, 115, 103, 32, 61, 32, 123, 125, 59, 10, 32, 32, 109, 115, 103, 91, 39, 109, 101, 116, 104, 111, 100, 39, 93, 32, 61, 32, 39, 103, 101, 116, 39, 59, 10, 32, 32, 109, 115, 103, 91, 39, 110, 97, 109, 101, 39, 93, 32, 61, 32, 116, 104, 105, 115, 46, 97, 116, 116, 114, 105, 98, 117, 116, 101, 78, 97, 109, 101, 59, 10, 32, 32, 109, 115, 103, 91, 39, 122, 111, 110, 101, 39, 93, 32, 61, 32, 122, 111, 110, 101, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 99, 114, 101, 97, 116, 101, 80, 114, 111, 109, 105, 115, 101, 40, 109, 115, 103, 41, 59, 10, 125, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 73, 110, 116, 101, 114, 102, 97, 99, 101, 40, 97, 116, 116, 110, 97, 109, 101, 41, 32, 123, 10, 32, 32, 118, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 67, 111, 109, 109, 111, 110, 67, 111, 110, 116, 114, 117, 99, 116, 111, 114, 40, 116, 104, 105, 115, 44, 32, 97, 116, 116, 110, 97, 109, 101, 41, 59, 10, 125, 10, 10, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 73, 110, 116, 101, 114, 102, 97, 99, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 32, 61, 32, 86, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 59, 10, 10, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 73, 110, 116, 101, 114, 102, 97, 99, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 46, 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 99, 97, 108, 108, 98, 97, 99, 107, 44, 32, 122, 111, 110, 101, 41, 32, 123, 10, 32, 32, 105, 102, 32, 40, 33, 122, 111, 110, 101, 41, 32, 122, 111, 110, 101, 32, 61, 32, 110, 101, 119, 32, 90, 111, 110, 101, 40, 41, 59, 10, 10, 32, 32, 118, 97, 114, 32, 109, 115, 103, 32, 61, 32, 123, 125, 59, 10, 32, 32, 109, 115, 103, 91, 39, 109, 101, 116, 104, 111, 100, 39, 93, 32, 61, 32, 39, 115, 117, 98, 115, 99, 114, 105, 98, 101, 39, 59, 10, 32, 32, 109, 115, 103, 91, 39, 110, 97, 109, 101, 39, 93, 32, 61, 32, 116, 104, 105, 115, 46, 97, 116, 116, 114, 105, 98, 117, 116, 101, 78, 97, 109, 101, 59, 10, 32, 32, 109, 115, 103, 91, 39, 122, 111, 110, 101, 39, 93, 32, 61, 32, 122, 111, 110, 101, 59, 10, 10, 32, 32, 101, 120, 116, 101, 110, 115, 105, 111, 110, 46, 112, 111, 115, 116, 77, 101, 115, 115, 97, 103, 101, 40, 74, 83, 79, 78, 46, 115, 116, 114, 105, 110, 103, 105, 102, 121, 40, 109, 115, 103, 41, 41, 59, 10, 10, 32, 32, 109, 115, 103, 91, 39, 99, 97, 108, 108, 98, 97, 99, 107, 39, 93, 32, 61, 32, 99, 97, 108, 108, 98, 97, 99, 107, 59, 10, 10, 32, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 46, 112, 117, 115, 104, 40, 109, 115, 103, 41, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 46, 108, 101, 110, 103, 116, 104, 32, 45, 32, 49, 59, 10, 125, 59, 10, 10, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 73, 110, 116, 101, 114, 102, 97, 99, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 46, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 104, 97, 110, 100, 108, 101, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 111, 98, 106, 32, 61, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 91, 104, 97, 110, 100, 108, 101, 93, 59, 10, 32, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 46, 115, 112, 108, 105, 99, 101, 40, 104, 97, 110, 100, 108, 101, 44, 32, 49, 41, 59, 10, 10, 32, 32, 118, 97, 114, 32, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 61, 32, 116, 114, 117, 101, 59, 10, 10, 32, 32, 102, 111, 114, 32, 40, 118, 97, 114, 32, 105, 32, 61, 32, 48, 59, 32, 105, 32, 60, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 46, 108, 101, 110, 103, 116, 104, 59, 32, 105, 43, 43, 41, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, 32, 116, 101, 115, 116, 79, 98, 106, 32, 61, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 91, 105, 93, 59, 10, 10, 32, 32, 32, 32, 105, 102, 32, 40, 116, 101, 115, 116, 79, 98, 106, 46, 110, 97, 109, 101, 32, 61, 61, 61, 32, 111, 98, 106, 46, 110, 97, 109, 101, 32, 38, 38, 32, 116, 101, 115, 116, 79, 98, 106, 46, 122, 111, 110, 101, 46, 101, 113, 117, 97, 108, 115, 40, 111, 98, 106, 46, 122, 111, 110, 101, 41, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 61, 32, 102, 97, 108, 115, 101, 59, 10, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 125, 10, 32, 32, 125, 10, 10, 32, 32, 105, 102, 32, 40, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 41, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, 32, 109, 115, 103, 32, 61, 32, 123, 125, 59, 10, 32, 32, 32, 32, 109, 115, 103, 91, 39, 109, 101, 116, 104, 111, 100, 39, 93, 32, 61, 32, 39, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 39, 59, 10, 32, 32, 32, 32, 109, 115, 103, 91, 39, 110, 97, 109, 101, 39, 93, 32, 61, 32, 116, 104, 105, 115, 46, 97, 116, 116, 114, 105, 98, 117, 116, 101, 78, 97, 109, 101, 59, 10, 32, 32, 32, 32, 109, 115, 103, 91, 39, 122, 111, 110, 101, 39, 93, 32, 61, 32, 111, 98, 106, 46, 122, 111, 110, 101, 59, 10, 10, 32, 32, 32, 32, 101, 120, 116, 101, 110, 115, 105, 111, 110, 46, 112, 111, 115, 116, 77, 101, 115, 115, 97, 103, 101, 40, 74, 83, 79, 78, 46, 115, 116, 114, 105, 110, 103, 105, 102, 121, 40, 109, 115, 103, 41, 41, 59, 10, 32, 32, 125, 10, 125, 59, 10, 10, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 73, 110, 116, 101, 114, 102, 97, 99, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 46, 115, 101, 116, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 40, 118, 97, 108, 117, 101, 44, 32, 122, 111, 110, 101, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 109, 115, 103, 32, 61, 32, 123, 125, 59, 10, 32, 32, 109, 115, 103, 91, 39, 109, 101, 116, 104, 111, 100, 39, 93, 32, 61, 32, 39, 115, 101, 116, 39, 59, 10, 32, 32, 109, 115, 103, 91, 39, 110, 97, 109, 101, 39, 93, 32, 61, 32, 116, 104, 105, 115, 46, 97, 116, 116, 114, 105, 98, 117, 116, 101, 78, 97, 109, 101, 59, 10, 32, 32, 109, 115, 103, 91, 39, 122, 111, 110, 101, 39, 93, 32, 61, 32, 122, 111, 110, 101, 59, 10, 32, 32, 109, 115, 103, 91, 39, 118, 97, 108, 117, 101, 39, 93, 32, 61, 32, 118, 97, 108, 117, 101, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 99, 114, 101, 97, 116, 101, 80, 114, 111, 109, 105, 115, 101, 40, 109, 115, 103, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 65, 115, 121, 110, 99, 67, 97, 108, 108, 40, 114, 101, 115, 111, 108, 118, 101, 44, 32, 114, 101, 106, 101, 99, 116, 41, 32, 123, 10, 32, 32, 116, 104, 105, 115, 46, 114, 101, 115, 111, 108, 118, 101, 32, 61, 32, 114, 101, 115, 111, 108, 118, 101, 59, 10, 32, 32, 116, 104, 105, 115, 46, 114, 101, 106, 101, 99, 116, 32, 61, 32, 114, 101, 106, 101, 99, 116, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 99, 114, 101, 97, 116, 101, 80, 114, 111, 109, 105, 115, 101, 40, 109, 115, 103, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 112, 114, 111, 109, 105, 115, 101, 32, 61, 32, 110, 101, 119, 32, 80, 114, 111, 109, 105, 115, 101, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, 114, 101, 115, 111, 108, 118, 101, 44, 32, 114, 101, 106, 101, 99, 116, 41, 32, 123, 10, 32, 32, 32, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 91, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 93, 32, 61, 32, 110, 101, 119, 32, 65, 115, 121, 110, 99, 67, 97, 108, 108, 40, 114, 101, 115, 111, 108, 118, 101, 44, 32, 114, 101, 106, 101, 99, 116, 41, 59, 10, 32, 32, 125, 41, 59, 10, 10, 32, 32, 109, 115, 103, 46, 97, 115, 121, 110, 99, 67, 97, 108, 108, 73, 100, 32, 61, 32, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 59, 10, 32, 32, 101, 120, 116, 101, 110, 115, 105, 111, 110, 46, 112, 111, 115, 116, 77, 101, 115, 115, 97, 103, 101, 40, 74, 83, 79, 78, 46, 115, 116, 114, 105, 110, 103, 105, 102, 121, 40, 109, 115, 103, 41, 41, 59, 10, 32, 32, 43, 43, 110, 101, 120, 116, 95, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 95, 105, 100, 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 112, 114, 111, 109, 105, 115, 101, 59, 10, 125, 10, 10, 119, 105, 110, 100, 111, 119, 46, 90, 111, 110, 101, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 122, 111, 110, 101, 41, 32, 123, 10, 32, 32, 116, 104, 105, 115, 46, 118, 97, 108, 117, 101, 32, 61, 32, 122, 111, 110, 101, 32, 63, 32, 122, 111, 110, 101, 32, 58, 32, 91, 93, 59, 10, 10, 32, 32, 79, 98, 106, 101, 99, 116, 46, 100, 101, 102, 105, 110, 101, 80, 114, 111, 112, 101, 114, 116, 121, 40, 116, 104, 105, 115, 44, 32, 39, 100, 114, 105, 118, 101, 114, 39, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 32, 101, 110, 117, 109, 101, 114, 97, 98, 108, 101, 58, 32, 102, 97, 108, 115, 101, 44, 32, 103, 101, 116, 58, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 110, 101, 119, 32, 90, 111, 110, 101, 40, 91, 39, 70, 114, 111, 110, 116, 39, 44, 32, 39, 76, 101, 102, 116, 39, 93, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 32, 125, 41, 59, 10, 125, 59, 10, 10, 119, 105, 110, 100, 111, 119, 46, 90, 111, 110, 101, 46, 112, 114, 111, 116, 111, 116, 121, 112, 101, 46, 101, 113, 117, 97, 108, 115, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 122, 111, 110, 101, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 105, 115, 95, 101, 113, 117, 97, 108, 32, 61, 32, 116, 114, 117, 101, 59, 10, 10, 32, 32, 102, 111, 114, 32, 40, 118, 97, 114, 32, 105, 32, 61, 32, 48, 59, 32, 105, 32, 60, 32, 122, 111, 110, 101, 46, 118, 97, 108, 117, 101, 46, 108, 101, 110, 103, 116, 104, 59, 32, 105, 43, 43, 41, 32, 123, 10, 32, 32, 32, 32, 105, 115, 95, 101, 113, 117, 97, 108, 32, 38, 61, 32, 116, 104, 105, 115, 46, 118, 97, 108, 117, 101, 46, 105, 110, 100, 101, 120, 79, 102, 40, 122, 111, 110, 101, 46, 118, 97, 108, 117, 101, 91, 105, 93, 41, 32, 33, 61, 61, 32, 45, 49, 59, 10, 32, 32, 125, 10, 10, 32, 32, 102, 111, 114, 32, 40, 118, 97, 114, 32, 105, 32, 61, 32, 48, 59, 32, 105, 32, 60, 32, 116, 104, 105, 115, 46, 118, 97, 108, 117, 101, 46, 108, 101, 110, 103, 116, 104, 59, 32, 105, 43, 43, 41, 32, 123, 10, 32, 32, 32, 32, 105, 115, 95, 101, 113, 117, 97, 108, 32, 38, 61, 32, 122, 111, 110, 101, 46, 118, 97, 108, 117, 101, 46, 105, 110, 100, 101, 120, 79, 102, 40, 116, 104, 105, 115, 46, 118, 97, 108, 117, 101, 91, 105, 93, 41, 32, 33, 61, 61, 32, 45, 49, 59, 10, 32, 32, 125, 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 105, 115, 95, 101, 113, 117, 97, 108, 59, 10, 125, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 80, 114, 111, 112, 101, 114, 116, 121, 40, 111, 98, 106, 44, 32, 112, 114, 111, 112, 41, 32, 123, 10, 32, 32, 79, 98, 106, 101, 99, 116, 46, 100, 101, 102, 105, 110, 101, 80, 114, 111, 112, 101, 114, 116, 121, 40, 111, 98, 106, 44, 32, 112, 114, 111, 112, 44, 32, 123, 32, 101, 110, 117, 109, 101, 114, 97, 98, 108, 101, 58, 32, 116, 114, 117, 101, 44, 32, 118, 97, 108, 117, 101, 58, 32, 110, 101, 119, 32, 86, 101, 104, 105, 99, 108, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 40, 112, 114, 111, 112, 41, 32, 125, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 111, 98, 106, 44, 32, 112, 114, 111, 112, 41, 32, 123, 10, 32, 32, 79, 98, 106, 101, 99, 116, 46, 100, 101, 102, 105, 110, 101, 80, 114, 111, 112, 101, 114, 116, 121, 40, 111, 98, 106, 44, 32, 112, 114, 111, 112, 44, 32, 123, 32, 101, 110, 117, 109, 101, 114, 97, 98, 108, 101, 58, 32, 116, 114, 117, 101, 44, 32, 118, 97, 108, 117, 101, 58, 32, 110, 101, 119, 32, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 73, 110, 116, 101, 114, 102, 97, 99, 101, 40, 112, 114, 111, 112, 41, 32, 125, 41, 59, 10, 125, 10, 10, 101, 120, 116, 101, 110, 115, 105, 111, 110, 46, 115, 101, 116, 77, 101, 115, 115, 97, 103, 101, 76, 105, 115, 116, 101, 110, 101, 114, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, 106, 115, 111, 110, 41, 32, 123, 10, 32, 32, 116, 114, 121, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, 32, 109, 115, 103, 32, 61, 32, 74, 83, 79, 78, 46, 112, 97, 114, 115, 101, 40, 106, 115, 111, 110, 41, 59, 10, 10, 32, 32, 32, 32, 115, 119, 105, 116, 99, 104, 32, 40, 109, 115, 103, 46, 109, 101, 116, 104, 111, 100, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 103, 101, 116, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 97, 110, 100, 108, 101, 80, 114, 111, 109, 105, 115, 101, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 122, 111, 110, 101, 115, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 97, 110, 100, 108, 101, 90, 111, 110, 101, 115, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 115, 117, 98, 115, 99, 114, 105, 98, 101, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 97, 110, 100, 108, 101, 83, 117, 98, 115, 99, 114, 105, 98, 101, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 115, 101, 116, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 97, 110, 100, 108, 101, 80, 114, 111, 109, 105, 115, 101, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 100, 101, 102, 97, 117, 108, 116, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 125, 10, 32, 32, 125, 32, 99, 97, 116, 99, 104, 32, 40, 101, 114, 114, 111, 114, 41, 32, 123, 10, 32, 32, 32, 32, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 40, 39, 69, 114, 114, 111, 114, 32, 105, 110, 32, 109, 101, 115, 115, 97, 103, 101, 32, 108, 105, 115, 116, 101, 110, 101, 114, 58, 32, 39, 32, 43, 32, 101, 114, 114, 111, 114, 41, 59, 10, 32, 32, 125, 10, 125, 41, 59, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 104, 97, 110, 100, 108, 101, 80, 114, 111, 109, 105, 115, 101, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 99, 98, 111, 98, 106, 32, 61, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 91, 109, 115, 103, 46, 97, 115, 121, 110, 99, 67, 97, 108, 108, 73, 100, 93, 59, 10, 10, 32, 32, 105, 102, 32, 40, 109, 115, 103, 46, 101, 114, 114, 111, 114, 41, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, 32, 101, 114, 114, 111, 114, 32, 61, 32, 123, 125, 59, 10, 32, 32, 32, 32, 101, 114, 114, 111, 114, 46, 101, 114, 114, 111, 114, 32, 61, 32, 109, 115, 103, 46, 118, 97, 108, 117, 101, 59, 10, 32, 32, 32, 32, 115, 119, 105, 116, 99, 104, 32, 40, 109, 115, 103, 46, 118, 97, 108, 117, 101, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 112, 101, 114, 109, 105, 115, 115, 105, 111, 110, 95, 100, 101, 110, 105, 101, 100, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 101, 114, 114, 111, 114, 46, 109, 101, 115, 115, 97, 103, 101, 32, 61, 32, 39, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 32, 100, 101, 110, 105, 101, 100, 39, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 105, 110, 118, 97, 108, 105, 100, 95, 111, 112, 101, 114, 97, 116, 105, 111, 110, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 101, 114, 114, 111, 114, 46, 109, 101, 115, 115, 97, 103, 101, 32, 61, 32, 39, 73, 110, 118, 97, 108, 105, 100, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 39, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 116, 105, 109, 101, 111, 117, 116, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 101, 114, 114, 111, 114, 46, 109, 101, 115, 115, 97, 103, 101, 32, 61, 32, 39, 79, 112, 101, 114, 97, 116, 105, 111, 110, 32, 116, 105, 109, 101, 100, 32, 111, 117, 116, 39, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 105, 110, 118, 97, 108, 105, 100, 95, 122, 111, 110, 101, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 101, 114, 114, 111, 114, 46, 109, 101, 115, 115, 97, 103, 101, 32, 61, 32, 39, 90, 111, 110, 101, 32, 105, 110, 118, 97, 108, 105, 100, 32, 111, 114, 32, 110, 111, 116, 32, 102, 111, 117, 110, 100, 39, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 99, 97, 115, 101, 32, 39, 117, 110, 107, 110, 111, 119, 110, 39, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 101, 114, 114, 111, 114, 46, 109, 101, 115, 115, 97, 103, 101, 32, 61, 32, 39, 65, 110, 32, 117, 110, 107, 110, 111, 119, 110, 32, 101, 114, 114, 111, 114, 32, 111, 99, 99, 117, 114, 101, 100, 39, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 32, 32, 100, 101, 102, 97, 117, 108, 116, 58, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 114, 101, 97, 107, 59, 10, 32, 32, 32, 32, 125, 10, 10, 32, 32, 32, 32, 99, 98, 111, 98, 106, 46, 114, 101, 106, 101, 99, 116, 40, 101, 114, 114, 111, 114, 41, 59, 10, 32, 32, 125, 32, 101, 108, 115, 101, 32, 123, 10, 32, 32, 32, 32, 99, 98, 111, 98, 106, 46, 114, 101, 115, 111, 108, 118, 101, 40, 109, 115, 103, 46, 118, 97, 108, 117, 101, 41, 59, 10, 32, 32, 125, 10, 10, 32, 32, 100, 101, 108, 101, 116, 101, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 91, 109, 115, 103, 46, 97, 115, 121, 110, 99, 67, 97, 108, 108, 73, 100, 93, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 104, 97, 110, 100, 108, 101, 90, 111, 110, 101, 115, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 32, 123, 10, 32, 32, 118, 97, 114, 32, 99, 98, 111, 98, 106, 32, 61, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 91, 109, 115, 103, 46, 97, 115, 121, 110, 99, 67, 97, 108, 108, 73, 100, 93, 59, 10, 10, 32, 32, 105, 102, 32, 40, 99, 98, 111, 98, 106, 41, 10, 32, 32, 32, 32, 99, 98, 111, 98, 106, 46, 114, 101, 115, 111, 108, 118, 101, 40, 110, 101, 119, 32, 90, 111, 110, 101, 40, 109, 115, 103, 46, 118, 97, 108, 117, 101, 41, 41, 59, 10, 125, 10, 10, 102, 117, 110, 99, 116, 105, 111, 110, 32, 104, 97, 110, 100, 108, 101, 83, 117, 98, 115, 99, 114, 105, 98, 101, 82, 101, 112, 108, 121, 40, 109, 115, 103, 41, 32, 123, 10, 32, 32, 100, 101, 108, 101, 116, 101, 32, 97, 115, 121, 110, 99, 95, 99, 97, 108, 108, 115, 91, 109, 115, 103, 46, 97, 115, 121, 110, 99, 67, 97, 108, 108, 73, 100, 93, 59, 10, 32, 32, 118, 97, 114, 32, 118, 97, 108, 117, 101, 32, 61, 32, 109, 115, 103, 46, 118, 97, 108, 117, 101, 59, 10, 32, 32, 118, 97, 108, 117, 101, 46, 122, 111, 110, 101, 32, 61, 32, 110, 101, 119, 32, 90, 111, 110, 101, 40, 118, 97, 108, 117, 101, 46, 122, 111, 110, 101, 41, 59, 10, 10, 32, 32, 102, 111, 114, 32, 40, 118, 97, 114, 32, 105, 32, 61, 32, 48, 59, 32, 105, 32, 60, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 46, 108, 101, 110, 103, 116, 104, 59, 32, 105, 43, 43, 41, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, 32, 105, 116, 114, 32, 61, 32, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 91, 105, 93, 59, 10, 32, 32, 32, 32, 118, 97, 114, 32, 105, 102, 97, 99, 101, 73, 115, 32, 61, 32, 40, 118, 97, 108, 117, 101, 46, 105, 110, 116, 101, 114, 102, 97, 99, 101, 78, 97, 109, 101, 46, 116, 111, 76, 111, 119, 101, 114, 67, 97, 115, 101, 40, 41, 32, 61, 61, 61, 32, 105, 116, 114, 46, 110, 97, 109, 101, 46, 116, 111, 76, 111, 119, 101, 114, 67, 97, 115, 101, 40, 41, 41, 59, 10, 32, 32, 32, 32, 105, 102, 32, 40, 105, 102, 97, 99, 101, 73, 115, 32, 61, 61, 61, 32, 116, 114, 117, 101, 32, 38, 38, 32, 118, 97, 108, 117, 101, 46, 122, 111, 110, 101, 46, 101, 113, 117, 97, 108, 115, 40, 105, 116, 114, 46, 122, 111, 110, 101, 41, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 105, 116, 114, 46, 99, 97, 108, 108, 98, 97, 99, 107, 40, 118, 97, 108, 117, 101, 41, 59, 10, 32, 32, 32, 32, 125, 10, 32, 32, 125, 10, 125, 10, 47, 47, 47, 32, 82, 117, 110, 110, 105, 110, 103, 115, 116, 97, 116, 117, 115, 32, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 58, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 118, 101, 104, 105, 99, 108, 101, 83, 112, 101, 101, 100, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 101, 110, 103, 105, 110, 101, 83, 112, 101, 101, 100, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 112, 111, 119, 101, 114, 116, 114, 97, 105, 110, 84, 111, 114, 113, 117, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 97, 99, 99, 101, 108, 101, 114, 97, 116, 111, 114, 80, 101, 100, 97, 108, 80, 111, 115, 105, 116, 105, 111, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 116, 104, 114, 111, 116, 116, 108, 101, 80, 111, 115, 105, 116, 105, 111, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 116, 114, 97, 110, 115, 109, 105, 115, 115, 105, 111, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 99, 114, 117, 105, 115, 101, 67, 111, 110, 116, 114, 111, 108, 83, 116, 97, 116, 117, 115, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 108, 105, 103, 104, 116, 83, 116, 97, 116, 117, 115, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 104, 111, 114, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 99, 104, 105, 109, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 102, 117, 101, 108, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 101, 110, 103, 105, 110, 101, 79, 105, 108, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 97, 99, 99, 101, 108, 101, 114, 97, 116, 105, 111, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 101, 110, 103, 105, 110, 101, 67, 111, 111, 108, 97, 110, 116, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 115, 116, 101, 101, 114, 105, 110, 103, 87, 104, 101, 101, 108, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 119, 104, 101, 101, 108, 84, 105, 99, 107, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 105, 103, 110, 105, 116, 105, 111, 110, 84, 105, 109, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 121, 97, 119, 82, 97, 116, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 98, 114, 97, 107, 101, 79, 112, 101, 114, 97, 116, 105, 111, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 98, 117, 116, 116, 111, 110, 69, 118, 101, 110, 116, 39, 41, 59, 10, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 110, 105, 103, 104, 116, 77, 111, 100, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 100, 114, 105, 118, 105, 110, 103, 77, 111, 100, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 98, 114, 97, 107, 101, 79, 112, 101, 114, 97, 116, 105, 111, 110, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 116, 105, 114, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 100, 111, 111, 114, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 100, 101, 102, 114, 111, 115, 116, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 99, 108, 105, 109, 97, 116, 101, 67, 111, 110, 116, 114, 111, 108, 39, 41, 59, 10, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 98, 97, 116, 116, 101, 114, 121, 83, 116, 97, 116, 117, 115, 39, 41, 59, 10, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 116, 101, 109, 112, 101, 114, 97, 116, 117, 114, 101, 39, 41, 59, 10, 95, 100, 101, 102, 105, 110, 101, 86, 101, 104, 105, 99, 108, 101, 83, 105, 103, 110, 97, 108, 80, 114, 111, 112, 101, 114, 116, 121, 40, 101, 120, 112, 111, 114, 116, 115, 44, 32, 39, 111, 100, 111, 109, 101, 116, 101, 114, 39, 41, 59, 10, 10, 10, 0 }; diff --git a/xwalk/vehicle_api.js b/xwalk/vehicle_api.js new file mode 100644 index 00000000..aeb721bf --- /dev/null +++ b/xwalk/vehicle_api.js @@ -0,0 +1,264 @@ +// 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 = {}; + +var subscriptions = []; + +function vehicleInterfaceCommonContructor(obj, attname) { + obj.attributeName = attname; + + var msg = {}; + msg['method'] = 'zones'; + msg['name'] = obj.attributeName; + + obj._zones = new Zone; + + var call = new AsyncCall(function(data) { + obj._zones = data; + }); + + async_calls[next_async_call_id] = call; + msg.asyncCallId = next_async_call_id; + ++next_async_call_id; + + extension.postMessage(JSON.stringify(msg)); + + Object.defineProperty(obj, 'zones', { get: function() { return obj._zones } }); +} + +function VehicleInterface(attname) { + vehicleInterfaceCommonContructor(this, attname); +} + +VehicleInterface.prototype.get = function(zone) { + var msg = {}; + msg['method'] = 'get'; + msg['name'] = this.attributeName; + msg['zone'] = zone; + + return createPromise(msg); +}; + +function VehicleSignalInterface(attname) { + vehicleInterfaceCommonContructor(this, attname); +} + +VehicleSignalInterface.prototype = VehicleInterface.prototype; + +VehicleSignalInterface.prototype.subscribe = function(callback, zone) { + if (!zone) zone = new Zone(); + + var msg = {}; + msg['method'] = 'subscribe'; + msg['name'] = this.attributeName; + msg['zone'] = zone; + + extension.postMessage(JSON.stringify(msg)); + + msg['callback'] = callback; + + subscriptions.push(msg); + + return subscriptions.length - 1; +}; + +VehicleSignalInterface.prototype.unsubscribe = function(handle) { + var obj = subscriptions[handle]; + subscriptions.splice(handle, 1); + + var unsubscribe = true; + + for (var i = 0; i < subscriptions.length; i++) { + var testObj = subscriptions[i]; + + if (testObj.name === obj.name && testObj.zone.equals(obj.zone)) { + unsubscribe = false; + break; + } + } + + if (unsubscribe) { + var msg = {}; + msg['method'] = 'unsubscribe'; + msg['name'] = this.attributeName; + msg['zone'] = obj.zone; + + extension.postMessage(JSON.stringify(msg)); + } +}; + +VehicleSignalInterface.prototype.set = function (value, zone) { + var msg = {}; + msg['method'] = 'set'; + msg['name'] = this.attributeName; + msg['zone'] = zone; + msg['value'] = value; + + 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; +} + +window.Zone = function(zone) { + this.value = zone ? zone : []; + + Object.defineProperty(this, 'driver', + { enumerable: false, get: function() { + return new Zone(['Front', 'Left']); + } }); +}; + +window.Zone.prototype.equals = function(zone) { + var is_equal = true; + + for (var i = 0; i < zone.value.length; i++) { + is_equal &= this.value.indexOf(zone.value[i]) !== -1; + } + + for (var i = 0; i < this.value.length; i++) { + is_equal &= zone.value.indexOf(this.value[i]) !== -1; + } + + return is_equal; +}; + +function _defineVehicleProperty(obj, prop) { + Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleInterface(prop) }); +} + +function _defineVehicleSignalProperty(obj, prop) { + Object.defineProperty(obj, prop, { enumerable: true, value: new VehicleSignalInterface(prop) }); +} + +extension.setMessageListener(function(json) { + try { + var msg = JSON.parse(json); + + switch (msg.method) { + case 'get': + handlePromiseReply(msg); + break; + case 'zones': + handleZonesReply(msg); + break; + case 'subscribe': + handleSubscribeReply(msg); + break; + case 'set': + handlePromiseReply(msg); + break; + default: + break; + } + } catch (error) { + console.log('Error in message listener: ' + error); + } +}); + +function handlePromiseReply(msg) { + var cbobj = async_calls[msg.asyncCallId]; + + if (msg.error) { + var error = {}; + error.error = msg.value; + switch (msg.value) { + case 'permission_denied': + error.message = 'Permission denied'; + break; + case 'invalid_operation': + error.message = 'Invalid operation'; + break; + case 'timeout': + error.message = 'Operation timed out'; + break; + case 'invalid_zone': + error.message = 'Zone invalid or not found'; + break; + case 'unknown': + error.message = 'An unknown error occured'; + break; + default: + break; + } + + cbobj.reject(error); + } else { + cbobj.resolve(msg.value); + } + + delete async_calls[msg.asyncCallId]; +} + +function handleZonesReply(msg) { + var cbobj = async_calls[msg.asyncCallId]; + + if (cbobj) + cbobj.resolve(new Zone(msg.value)); +} + +function handleSubscribeReply(msg) { + delete async_calls[msg.asyncCallId]; + var value = msg.value; + value.zone = new Zone(value.zone); + + for (var i = 0; i < subscriptions.length; i++) { + var itr = subscriptions[i]; + var ifaceIs = (value.interfaceName.toLowerCase() === itr.name.toLowerCase()); + if (ifaceIs === true && value.zone.equals(itr.zone)) { + itr.callback(value); + } + } +} +/// Runningstatus attributes: +_defineVehicleSignalProperty(exports, 'vehicleSpeed'); +_defineVehicleSignalProperty(exports, 'engineSpeed'); +_defineVehicleSignalProperty(exports, 'powertrainTorque'); +_defineVehicleSignalProperty(exports, 'acceleratorPedalPosition'); +_defineVehicleSignalProperty(exports, 'throttlePosition'); +_defineVehicleSignalProperty(exports, 'transmission'); +_defineVehicleSignalProperty(exports, 'cruiseControlStatus'); +_defineVehicleSignalProperty(exports, 'lightStatus'); +_defineVehicleSignalProperty(exports, 'horn'); +_defineVehicleSignalProperty(exports, 'chime'); +_defineVehicleSignalProperty(exports, 'fuel'); +_defineVehicleSignalProperty(exports, 'engineOil'); +_defineVehicleSignalProperty(exports, 'acceleration'); +_defineVehicleSignalProperty(exports, 'engineCoolant'); +_defineVehicleSignalProperty(exports, 'steeringWheel'); +_defineVehicleSignalProperty(exports, 'wheelTick'); +_defineVehicleSignalProperty(exports, 'ignitionTime'); +_defineVehicleSignalProperty(exports, 'yawRate'); +_defineVehicleSignalProperty(exports, 'brakeOperation'); +_defineVehicleSignalProperty(exports, 'buttonEvent'); + +_defineVehicleSignalProperty(exports, 'nightMode'); +_defineVehicleSignalProperty(exports, 'drivingMode'); +_defineVehicleSignalProperty(exports, 'brakeOperation'); +_defineVehicleSignalProperty(exports, 'tire'); +_defineVehicleSignalProperty(exports, 'door'); +_defineVehicleSignalProperty(exports, 'defrost'); +_defineVehicleSignalProperty(exports, 'climateControl'); + +_defineVehicleSignalProperty(exports, 'batteryStatus'); + +_defineVehicleSignalProperty(exports, 'temperature'); +_defineVehicleSignalProperty(exports, 'odometer'); + + diff --git a/xwalk/vehicle_extension.cc b/xwalk/vehicle_extension.cc new file mode 100644 index 00000000..a021c142 --- /dev/null +++ b/xwalk/vehicle_extension.cc @@ -0,0 +1,29 @@ +// 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_extension.h" + +#include "vehicle_instance.h" + +common::Extension* CreateExtension() { + return new VehicleExtension(); +} + +extern const char kSource_vehicle_api[]; + +VehicleExtension::VehicleExtension() { + SetExtensionName("navigator.vehicle"); + SetJavaScriptAPI(kSource_vehicle_api); + + const char* entry_points[] = {"Zone", NULL}; + + SetExtraJSEntryPoints(entry_points); +} + +VehicleExtension::~VehicleExtension() { +} + +common::Instance* VehicleExtension::CreateInstance() { + return new VehicleInstance; +} diff --git a/xwalk/vehicle_extension.h b/xwalk/vehicle_extension.h new file mode 100644 index 00000000..ebd50811 --- /dev/null +++ b/xwalk/vehicle_extension.h @@ -0,0 +1,20 @@ +// 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_ diff --git a/xwalk/vehicle_instance.cc b/xwalk/vehicle_instance.cc new file mode 100644 index 00000000..9a8091d8 --- /dev/null +++ b/xwalk/vehicle_instance.cc @@ -0,0 +1,134 @@ +// 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_instance.h" + +#include <abstractpropertytype.h> + +#include <algorithm> +#include <string> + +#include "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(); + + Zone::Type amb_zone = 0; + if (v.contains("zone")) { + picojson::value zone = v.get("zone"); + if (zone.is<picojson::object>() && zone.contains("value")) { + picojson::array zones = zone.get("value").get<picojson::array>(); + amb_zone = ZoneToAMBZone(zones); + } else { + int callback_id = -1; + if (v.contains("asyncCallId")) + callback_id = v.get("asyncCallId").get<double>(); + PostError(callback_id, method, "invalid_zone"); + return; + } + } + + if (method == "get") { + std::string attribute = v.get("name").to_str(); + int callback_id = v.get("asyncCallId").get<double>(); + Zone::Type amb_zone = 0; + + std::transform(attribute.begin(), attribute.begin() + 1, attribute.begin(), + ::toupper); + + vehicle_->Get(attribute, amb_zone, callback_id); + } else if (method == "zones") { + std::string attribute = v.get("name").to_str(); + int callback_id = v.get("asyncCallId").get<double>(); + std::transform(attribute.begin(), attribute.begin() + 1, attribute.begin(), + ::toupper); + + vehicle_->GetZones(attribute, callback_id); + } else if (method == "subscribe") { + std::string attribute = v.get("name").to_str(); + std::transform(attribute.begin(), attribute.begin() + 1, attribute.begin(), + ::toupper); + + vehicle_->Subscribe(attribute, amb_zone); + } else if (method == "unsubscribe") { + std::string attribute = v.get("name").to_str(); + std::transform(attribute.begin(), attribute.begin() + 1, attribute.begin(), + ::toupper); + + vehicle_->Unsubscribe(attribute, amb_zone); + } else if (method == "set") { + std::string attribute = v.get("name").to_str(); + int callback_id = v.get("asyncCallId").get<double>(); + Zone::Type amb_zone = 0; + + std::transform(attribute.begin(), attribute.begin() + 1, attribute.begin(), + ::toupper); + + if (!v.get("value").is<picojson::object>()) { + PostError(callback_id, "set", "invalid_operation"); + } + picojson::object value = v.get("value").get<picojson::object>(); + + vehicle_->Set(attribute, value, 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; +} + +void VehicleInstance::PostError(double callback_id, const std::string& method, + const std::string& error) { + picojson::object msg; + msg["method"] = picojson::value(method); + msg["error"] = picojson::value(true); + msg["value"] = picojson::value(error); + if (callback_id != -1) { + msg["asyncCallId"] = + picojson::value(static_cast<double>(callback_id)); + } + + std::string message = picojson::value(msg).serialize(); + + DebugOut() << "Error Reply message: " << message << endl; + + PostMessage(message.c_str()); +} diff --git a/xwalk/vehicle_instance.h b/xwalk/vehicle_instance.h new file mode 100644 index 00000000..33dc8ba8 --- /dev/null +++ b/xwalk/vehicle_instance.h @@ -0,0 +1,32 @@ +// 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 <string> + +#include "common/extension.h" +#include "common/picojson.h" +#include "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); + + void PostError(double callback_id, const std::string& method, + const std::string& error); + + Vehicle* vehicle_; +}; + +#endif // VEHICLE_VEHICLE_INSTANCE_H_ |