diff options
Diffstat (limited to 'plugins/cansimplugin/cansimplugin.cpp')
-rw-r--r-- | plugins/cansimplugin/cansimplugin.cpp | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/plugins/cansimplugin/cansimplugin.cpp b/plugins/cansimplugin/cansimplugin.cpp new file mode 100644 index 00000000..b609b3f9 --- /dev/null +++ b/plugins/cansimplugin/cansimplugin.cpp @@ -0,0 +1,389 @@ +/* +Copyright (C) 2012 Intel Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <boost/assert.hpp> +#include <glib.h> +#include <deque> +#include <json.h> + +#include <vehicleproperty.h> +#include <listplusplus.h> +#include <ambplugin.h> + +#include <logger.h> + +#include "cansimplugin.h" + +static const char* DEFAULT_CAN_IF_NAME = "vcan0"; + +//---------------------------------------------------------------------------- +// CANSimPlugin +//---------------------------------------------------------------------------- + +// library exported function for plugin loader +extern "C" void create(AbstractRoutingEngine* routingengine, std::map<std::string, std::string> config) +{ +#ifndef UNIT_TESTS + DEBUG_CONF("cansimplugin", + CUtil::Logger::file_off|CUtil::Logger::screen_on, + CUtil::Logger::EInfo, CUtil::Logger::EInfo + ); +#endif + AmbPlugin<CANSimPlugin> * plugin = new AmbPlugin<CANSimPlugin>(routingengine, config); + plugin->init(); +} + +//---------------------------------------------------------------------------- +// CANSimPlugin +//---------------------------------------------------------------------------- + +const VehicleProperty::Property MappingTable = "MappingTable"; + +// +// IVIPOC signals +// +const VehicleProperty::Property BatteryStatus = "BatteryStatus"; +PROPERTYTYPEBASIC(BatteryStatus, uint16_t) +const VehicleProperty::Property FullBatteryRange = "FullBatteryRange"; +PROPERTYTYPEBASIC(FullBatteryRange, uint16_t) +const VehicleProperty::Property Weather = "Weather"; +PROPERTYTYPEBASIC(Weather, uint16_t) +const VehicleProperty::Property AvgKW = "AvgKW"; +PROPERTYTYPEBASIC(AvgKW, double) + +#define ADDPROPERTY(property, default_value, zone_value) \ + addPropertySupport(zone_value, [](){ \ + return new property ## Type(default_value); \ + }) + +CANSimPlugin::CANSimPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) : + AmbPluginImpl(re, config, parent) +{ + auto it = config.find("interfaces"); + if(it != config.end() && it->second.length()){ + std::unique_ptr<json_object, decltype(&json_object_put)> rootobject(json_tokener_parse(it->second.c_str()), &json_object_put); + if(rootobject){ + g_assert(json_object_get_type(rootobject.get())==json_type_array); + array_list *ifacelist = json_object_get_array(rootobject.get()); + if (ifacelist) { + for(int i=0; i < array_list_length(ifacelist); ++i) + { + json_object* obj = (json_object*)array_list_get_idx(ifacelist,i); + const char* str = obj ? json_object_get_string(obj) : nullptr; + if(str){ + interfaces[str] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this))); + } + } + } + } + } + // Default interface if none has been configured. + if(interfaces.empty()){ + interfaces[DEFAULT_CAN_IF_NAME] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this))); + } + + addPropertySupport( + Zone::None, + [](){ + StringPropertyType *s = new StringPropertyType(MappingTable, ""); + s->zone = Zone::None; + return s; + } + ); + + // + // IVIPOC signals + // + ADDPROPERTY(VehicleProperty::ChildLockStatus, false, Zone::None); + ADDPROPERTY(VehicleProperty::LightHead, false, Zone::None); + ADDPROPERTY(VehicleProperty::LightParking, false, Zone::None); + ADDPROPERTY(VehicleProperty::AirConditioning, false, Zone::None); + ADDPROPERTY(BatteryStatus, 58, Zone::None); + ADDPROPERTY(FullBatteryRange, 350, Zone::None); + ADDPROPERTY(VehicleProperty::ExteriorTemperature, 74, Zone::None); + ADDPROPERTY(VehicleProperty::InteriorTemperature, 68, Zone::None); + ADDPROPERTY(VehicleProperty::FrontWheelRadius, 0, Zone::None); + ADDPROPERTY(Weather, 1, Zone::None); + ADDPROPERTY(AvgKW, 28, Zone::None); + ADDPROPERTY(VehicleProperty::VehicleSpeed, 65, Zone::None); + ADDPROPERTY(VehicleProperty::Odometer, 75126, Zone::None); + ADDPROPERTY(VehicleProperty::TransmissionShiftPosition, Transmission::Drive, Zone::None); + ADDPROPERTY(VehicleProperty::NightMode, false, Zone::None); + ADDPROPERTY(VehicleProperty::ExteriorBrightness, 1000, Zone::None); + // HVAC + ADDPROPERTY(VehicleProperty::LightHazard, false, Zone::None); + ADDPROPERTY(VehicleProperty::SeatHeater, 0, Zone::FrontLeft); + ADDPROPERTY(VehicleProperty::SeatHeater, 0, Zone::FrontRight); + ADDPROPERTY(VehicleProperty::AirRecirculation, false, Zone::None); + ADDPROPERTY(VehicleProperty::AirflowDirection, HVAC::Front, Zone::None); + ADDPROPERTY(VehicleProperty::FanSpeed, 200, Zone::None); + ADDPROPERTY(VehicleProperty::TargetTemperature, 68, Zone::Left); + ADDPROPERTY(VehicleProperty::TargetTemperature, 68, Zone::Right); + + ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Front); + ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Rear); + + ADDPROPERTY(VehicleProperty::VehiclePowerMode, Power::Run, Zone::None); + // TirePresure + ADDPROPERTY(VehicleProperty::TirePressure, 2.3, Zone::FrontLeft); + ADDPROPERTY(VehicleProperty::TirePressure, 2.3, Zone::FrontRight); + ADDPROPERTY(VehicleProperty::TirePressure, 2.4, Zone::RearLeft); + ADDPROPERTY(VehicleProperty::TirePressure, 2.4, Zone::RearRight); +} + +CANSimPlugin::~CANSimPlugin() +{ + for(auto it = interfaces.begin(); it != interfaces.end(); ++it){ + it->second->stop(); + } +} + +void CANSimPlugin::init() +{ + AmbPluginImpl::init(); + for(auto it = interfaces.begin(); it != interfaces.end(); ++it){ + it->second->start(it->first.c_str()); + } +} + +void CANSimPlugin::supportedChanged(const PropertyList& supportedProperties) +{ + PropertyList s = const_cast<PropertyList&>(supportedProperties); + removeOne(&s, MappingTable);// CANSimPlugin has own copy of the PropertyList from AmbPlugin + createMappingTable(supportedProperties); +} + +int CANSimPlugin::supportedOperations() const +{ + return AbstractSource::Get | AbstractSource::Set; +} + +void CANSimPlugin::createMappingTable(const PropertyList& /*supported*/) +{ + // + // Local helper classes + // + class JsonObject : public std::unique_ptr<json_object, decltype(&json_object_put)> + { + public: + JsonObject(json_object* object) : std::unique_ptr<json_object, decltype(&json_object_put)>(object, &json_object_put) {} + }; + + class PROPERTY{ + public: + PROPERTY(const VehicleProperty::Property& propertyName, const Zone::Type& z, int canId) : + name(propertyName), + zone(z), + can_id(canId) + { + } + PROPERTY(const PROPERTY& other) = delete; + PROPERTY& operator=(const PROPERTY& other) = delete; + PROPERTY(PROPERTY&& other) = default; + PROPERTY& operator=(PROPERTY&& other) = default; + JsonObject toJson() + { + JsonObject prop(json_object_new_object()); + json_object_object_add(prop.get(), "can_id", json_object_new_int(can_id)); + json_object_object_add(prop.get(), "name", json_object_new_string(name.c_str())); + json_object_object_add(prop.get(), "zone", json_object_new_int(static_cast<int>(zone))); + return prop; + } + private: + std::string name; + Zone::Type zone; + int can_id; + }; + + // + PropertyList allProperties(VehicleProperty::capabilities()); + + removeOne(&allProperties, MappingTable); + + // + // Create mapping table in JSON format + // + map< std::string, std::deque<PROPERTY> > table; + PropertyList addedProperties; + PropertyList removedProperties; + std::map< canid_t, std::tuple< std::string, VehicleProperty::Property, Zone::Type> > newMappingTable; + int can_id = 10; // Let's have a space for a special messages. Just in case .... in the future. + for(PropertyList::const_iterator propIt = allProperties.begin(); propIt != allProperties.end(); ++propIt) + { + VehicleProperty::Property propertyName(*propIt); + + std::vector<std::string> sources(routingEngine->sourcesForProperty(propertyName)); + size_t size = sources.size(); + + bool IAmTheSource = contains(sources, uuid()); + + if(size == 0 || size == 1 && IAmTheSource) { + if( size == 0 ){ + // I'm the source from now + ZonePropertyType& zonePropType = properties[propertyName]; + std::shared_ptr<AbstractPropertyType> value(VehicleProperty::getPropertyTypeForPropertyNameValue(propertyName)); + if(value){ + value->zone = Zone::None; + zonePropType.insert(make_pair(Zone::None, value)); + addedProperties.push_back(propertyName); + } + else{ + properties.erase(propertyName); + } + } + std::string source(uuid()); + //PropertyInfo info(routingEngine->getPropertyInfo(propertyName,source)); + //Zone::ZoneList zones(info.zones()); + //if(zones.empty()) + Zone::ZoneList zones; + { + for(int i = 0; i< 10; ++i){ + Zone::Type zone(Zone::None); + if(i) + zone = static_cast<Zone::Type>(1 << i); + zones.push_back(zone); + } + zones.push_back(Zone::FrontRight); + zones.push_back(Zone::FrontLeft); + zones.push_back(Zone::MiddleRight); + zones.push_back(Zone::MiddleLeft); + zones.push_back(Zone::RearRight); + zones.push_back(Zone::RearLeft); + } + for( auto z=zones.begin(); z != zones.end(); ++z ){ + table[source].push_back(PROPERTY(propertyName, *z, can_id)); + newMappingTable[can_id++] = make_tuple(source, propertyName, *z); + } + } + else if(IAmTheSource){ + // I'm the source, and there is another source + properties.erase(propertyName);// I don't need to simulate it anymore + removedProperties.push_back(propertyName); + } + } + + if(addedProperties.size() || removedProperties.size()) { + JsonObject sources(json_object_new_array()); + for(auto it = table.begin(); it != table.end(); ++it) { + // one source object: + JsonObject source(json_object_new_object()); + JsonObject description(json_object_new_object()); + json_object_object_add(description.get(), "guid", json_object_new_string(it->first.c_str())); + json_object_object_add(source.get(), "source", description.release()); + // signals: + JsonObject sigs(json_object_new_array()); + for(auto signalIt = it->second.begin(); signalIt != it->second.end(); ++signalIt) { + json_object_array_add(sigs.get(), signalIt->toJson().release()); + } + // add signals into source + json_object_object_add(source.get(), "signals", sigs.release()); + // add one source into sources array + json_object_array_add(sources.get(), source.release()); + } + // result json: + JsonObject result(json_object_new_object()); + json_object_object_add(result.get(), "sources", sources.release()); + + std::string mappingTableValue(json_object_to_json_string(result.get())); + + std::replace(mappingTableValue.begin(), mappingTableValue.end(), '"', '\'');// replace all " to ' + auto tableProperty = properties[MappingTable][Zone::None]; + if(tableProperty){ + // we have a new MappingTable + mappingTable.swap(newMappingTable); + tableProperty->setValue(mappingTableValue); + routingEngine->updateProperty(tableProperty.get(), uuid()); + } + + routingEngine->updateSupported(addedProperties, removedProperties, &source); + } +} + +// from CANObserver +void CANSimPlugin::errorOccured(CANObserver::CANError error) +{ + (void) error; + LOG_INFO( "CANSimPlugin::errorOccured() not implemented "<< std::endl ); +} + +void CANSimPlugin::standardFrameReceived(const can_frame& frame) +{ + (void) frame; + LOG_INFO( "CANSimPlugin::standardFrameReceived() not implemented "<< std::endl ); +} + +void CANSimPlugin::extendedFrameReceived(const can_frame& frame) +{ + LOG_INFO("CANSimPlugin::extendedFrameReceived()"); + printFrame(frame); + + auto it = mappingTable.find(frame.can_id); + if( it == mappingTable.end()){ + LOG_WARNING("can_id not found"); + return; + } + + std::string source(std::get<0>(it->second)); + VehicleProperty::Property name(std::get<1>(it->second)); + Zone::Type zone(std::get<2>(it->second)); + AbstractPropertyType* value = findPropertyType(name, zone); + if(!value) + return; + + std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(value->toVariant(), &g_variant_unref); + std::unique_ptr<GVariant, decltype(&g_variant_unref)> v_untrusted( + g_variant_new_from_data( g_variant_get_type(v.release()), frame.data, frame.can_dlc, FALSE, nullptr, nullptr), + &g_variant_unref + ); + std::unique_ptr<GVariant, decltype(&g_variant_unref)> v_normal(g_variant_get_normal_form(v_untrusted.release()), &g_variant_unref); + if(g_variant_is_normal_form(v_normal.get())) { + value->fromVariant(v_normal.get()); + routingEngine->updateProperty(value, source); + } + else{ + LOG_ERROR("Can't convert value from CAN to GVariant"); + } +} + +void CANSimPlugin::errorFrameReceived(const can_frame& frame) +{ + LOG_INFO("CANSimPlugin::errorFrameReceived()"); + printFrame(frame); +} + +void CANSimPlugin::remoteTransmissionRequest(const can_frame& frame) +{ + (void) frame; + LOG_INFO( "CANSimPlugin::remoteTransmissionRequest() not implemented "<< std::endl ); +} + +void CANSimPlugin::printFrame(const can_frame& frame) const +{ + LOG_INFO( "CANSimPlugin::printFrame can_id: " << std::hex << frame.can_id << std::dec << endl ); + LOG_INFO( "CANSimPlugin::printFrame can_dlc: " << int(frame.can_dlc) << endl ); + + std::stringstream ss; + for(int i=0; i<frame.can_dlc; ++i){ + ss << " " << std::hex << (int)(frame.data[i]); + } + ss << std::dec; + + LOG_INFO( "CANSimPlugin::printFrame can data" << ss.str() << endl ); +} + + |