2 Copyright (C) 2012 Intel Corporation
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <boost/assert.hpp>
23 #include <vehicleproperty.h>
24 #include <listplusplus.h>
27 #include <ambplugin.h>
29 #include "cansimplugin.h"
31 static const char* DEFAULT_CAN_IF_NAME = "vcan0";
33 //----------------------------------------------------------------------------
35 //----------------------------------------------------------------------------
37 // library exported function for plugin loader
38 extern "C" void create(AbstractRoutingEngine* routingengine, std::map<std::string, std::string> config)
41 DEBUG_CONF("cansimplugin",
42 CUtil::Logger::file_off|CUtil::Logger::screen_on,
43 CUtil::Logger::EInfo, CUtil::Logger::EInfo
46 AmbPlugin<CANSimPlugin> * plugin = new AmbPlugin<CANSimPlugin>(routingengine, config);
50 //----------------------------------------------------------------------------
52 //----------------------------------------------------------------------------
54 const VehicleProperty::Property MappingTable = "MappingTable";
59 const VehicleProperty::Property BatteryStatus = "BatteryStatus";
60 PROPERTYTYPEBASIC(BatteryStatus, uint16_t)
61 const VehicleProperty::Property FullBatteryRange = "FullBatteryRange";
62 PROPERTYTYPEBASIC(FullBatteryRange, uint16_t)
63 const VehicleProperty::Property Weather = "Weather";
64 PROPERTYTYPEBASIC(Weather, uint16_t)
65 const VehicleProperty::Property AvgKW = "AvgKW";
66 PROPERTYTYPEBASIC(AvgKW, double)
68 #define ADDPROPERTY(property, default_value, zone_value) \
69 addPropertySupport(zone_value, [](){ \
70 return new property ## Type(default_value); \
73 CANSimPlugin::CANSimPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
74 AmbPluginImpl(re, config, parent)
76 auto it = config.find("interfaces");
77 if(it != config.end() && it->second.length()){
78 std::unique_ptr<json_object, decltype(&json_object_put)> rootobject(json_tokener_parse(it->second.c_str()), &json_object_put);
80 g_assert(json_object_get_type(rootobject.get())==json_type_array);
81 array_list *ifacelist = json_object_get_array(rootobject.get());
83 for(int i=0; i < array_list_length(ifacelist); ++i)
85 json_object* obj = (json_object*)array_list_get_idx(ifacelist,i);
86 const char* str = obj ? json_object_get_string(obj) : nullptr;
88 interfaces[str] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
94 // Default interface if none has been configured.
95 if(interfaces.empty()){
96 interfaces[DEFAULT_CAN_IF_NAME] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
102 StringPropertyType *s = new StringPropertyType(MappingTable, "");
103 s->zone = Zone::None;
111 ADDPROPERTY(VehicleProperty::ChildLockStatus, false, Zone::None);
112 ADDPROPERTY(VehicleProperty::LightHead, false, Zone::None);
113 ADDPROPERTY(VehicleProperty::LightParking, false, Zone::None);
114 ADDPROPERTY(VehicleProperty::AirConditioning, false, Zone::None);
115 ADDPROPERTY(BatteryStatus, 58, Zone::None);
116 ADDPROPERTY(FullBatteryRange, 350, Zone::None);
117 ADDPROPERTY(VehicleProperty::ExteriorTemperature, 74, Zone::None);
118 ADDPROPERTY(VehicleProperty::InteriorTemperature, 68, Zone::None);
119 ADDPROPERTY(VehicleProperty::FrontWheelRadius, 0, Zone::None);
120 ADDPROPERTY(Weather, 1, Zone::None);
121 ADDPROPERTY(AvgKW, 28, Zone::None);
122 ADDPROPERTY(VehicleProperty::VehicleSpeed, 65, Zone::None);
123 ADDPROPERTY(VehicleProperty::Odometer, 75126, Zone::None);
124 ADDPROPERTY(VehicleProperty::TransmissionShiftPosition, Transmission::Drive, Zone::None);
125 ADDPROPERTY(VehicleProperty::NightMode, false, Zone::None);
126 ADDPROPERTY(VehicleProperty::ExteriorBrightness, 1000, Zone::None);
128 ADDPROPERTY(VehicleProperty::LightHazard, false, Zone::None);
129 ADDPROPERTY(VehicleProperty::SeatHeater, 0, Zone::FrontLeft);
130 ADDPROPERTY(VehicleProperty::SeatHeater, 0, Zone::FrontRight);
131 ADDPROPERTY(VehicleProperty::AirRecirculation, false, Zone::None);
132 ADDPROPERTY(VehicleProperty::AirflowDirection, HVAC::Front, Zone::None);
133 ADDPROPERTY(VehicleProperty::FanSpeed, 200, Zone::None);
134 ADDPROPERTY(VehicleProperty::TargetTemperature, 68, Zone::Left);
135 ADDPROPERTY(VehicleProperty::TargetTemperature, 68, Zone::Right);
137 ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Front);
138 ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Rear);
140 ADDPROPERTY(VehicleProperty::VehiclePowerMode, Power::Run, Zone::None);
142 ADDPROPERTY(VehicleProperty::TirePressure, 2.3, Zone::FrontLeft);
143 ADDPROPERTY(VehicleProperty::TirePressure, 2.3, Zone::FrontRight);
144 ADDPROPERTY(VehicleProperty::TirePressure, 2.4, Zone::RearLeft);
145 ADDPROPERTY(VehicleProperty::TirePressure, 2.4, Zone::RearRight);
148 CANSimPlugin::~CANSimPlugin()
150 for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
155 void CANSimPlugin::init()
157 AmbPluginImpl::init();
158 for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
159 it->second->start(it->first.c_str());
163 void CANSimPlugin::supportedChanged(const PropertyList& supportedProperties)
165 PropertyList s = const_cast<PropertyList&>(supportedProperties);
166 removeOne(&s, MappingTable);// CANSimPlugin has own copy of the PropertyList from AmbPlugin
167 createMappingTable(supportedProperties);
170 int CANSimPlugin::supportedOperations() const
172 return AbstractSource::Get | AbstractSource::Set;
175 void CANSimPlugin::createMappingTable(const PropertyList& /*supported*/)
178 // Local helper classes
180 class JsonObject : public std::unique_ptr<json_object, decltype(&json_object_put)>
183 JsonObject(json_object* object) : std::unique_ptr<json_object, decltype(&json_object_put)>(object, &json_object_put) {}
188 PROPERTY(const VehicleProperty::Property& propertyName, const Zone::Type& z, int canId) :
194 PROPERTY(const PROPERTY& other) = delete;
195 PROPERTY& operator=(const PROPERTY& other) = delete;
196 PROPERTY(PROPERTY&& other) = default;
197 PROPERTY& operator=(PROPERTY&& other) = default;
200 JsonObject prop(json_object_new_object());
201 json_object_object_add(prop.get(), "can_id", json_object_new_int(can_id));
202 json_object_object_add(prop.get(), "name", json_object_new_string(name.c_str()));
203 json_object_object_add(prop.get(), "zone", json_object_new_int(static_cast<int>(zone)));
213 PropertyList allProperties(VehicleProperty::capabilities());
215 removeOne(&allProperties, MappingTable);
218 // Create mapping table in JSON format
220 map< std::string, std::deque<PROPERTY> > table;
221 PropertyList addedProperties;
222 PropertyList removedProperties;
223 std::map< canid_t, std::tuple< std::string, VehicleProperty::Property, Zone::Type> > newMappingTable;
224 int can_id = 10; // Let's have a space for a special messages. Just in case .... in the future.
225 for(PropertyList::const_iterator propIt = allProperties.begin(); propIt != allProperties.end(); ++propIt)
227 VehicleProperty::Property propertyName(*propIt);
229 std::vector<std::string> sources(routingEngine->sourcesForProperty(propertyName));
230 size_t size = sources.size();
232 bool IAmTheSource = contains(sources, uuid());
234 if(size == 0 || size == 1 && IAmTheSource) {
236 // I'm the source from now
237 ZonePropertyType& zonePropType = properties[propertyName];
238 std::shared_ptr<AbstractPropertyType> value(VehicleProperty::getPropertyTypeForPropertyNameValue(propertyName));
240 value->zone = Zone::None;
241 zonePropType.insert(make_pair(Zone::None, value));
242 addedProperties.push_back(propertyName);
245 properties.erase(propertyName);
248 std::string source(uuid());
249 //PropertyInfo info(routingEngine->getPropertyInfo(propertyName,source));
250 //Zone::ZoneList zones(info.zones());
252 Zone::ZoneList zones;
254 for(int i = 0; i< 10; ++i){
255 Zone::Type zone(Zone::None);
257 zone = static_cast<Zone::Type>(1 << i);
258 zones.push_back(zone);
260 zones.push_back(Zone::FrontRight);
261 zones.push_back(Zone::FrontLeft);
262 zones.push_back(Zone::MiddleRight);
263 zones.push_back(Zone::MiddleLeft);
264 zones.push_back(Zone::RearRight);
265 zones.push_back(Zone::RearLeft);
267 for( auto z=zones.begin(); z != zones.end(); ++z ){
268 table[source].push_back(PROPERTY(propertyName, *z, can_id));
269 newMappingTable[can_id++] = make_tuple(source, propertyName, *z);
272 else if(IAmTheSource){
273 // I'm the source, and there is another source
274 properties.erase(propertyName);// I don't need to simulate it anymore
275 removedProperties.push_back(propertyName);
279 if(addedProperties.size() || removedProperties.size()) {
280 JsonObject sources(json_object_new_array());
281 for(auto it = table.begin(); it != table.end(); ++it) {
282 // one source object:
283 JsonObject source(json_object_new_object());
284 JsonObject description(json_object_new_object());
285 json_object_object_add(description.get(), "guid", json_object_new_string(it->first.c_str()));
286 json_object_object_add(source.get(), "source", description.release());
288 JsonObject sigs(json_object_new_array());
289 for(auto signalIt = it->second.begin(); signalIt != it->second.end(); ++signalIt) {
290 json_object_array_add(sigs.get(), signalIt->toJson().release());
292 // add signals into source
293 json_object_object_add(source.get(), "signals", sigs.release());
294 // add one source into sources array
295 json_object_array_add(sources.get(), source.release());
298 JsonObject result(json_object_new_object());
299 json_object_object_add(result.get(), "sources", sources.release());
301 std::string mappingTableValue(json_object_to_json_string(result.get()));
303 std::replace(mappingTableValue.begin(), mappingTableValue.end(), '"', '\'');// replace all " to '
304 auto tableProperty = properties[MappingTable][Zone::None];
306 // we have a new MappingTable
307 mappingTable.swap(newMappingTable);
308 tableProperty->setValue(mappingTableValue);
309 routingEngine->updateProperty(tableProperty.get(), uuid());
312 routingEngine->updateSupported(addedProperties, removedProperties, &source);
317 void CANSimPlugin::errorOccured(CANObserver::CANError error)
320 LOG_INFO( "CANSimPlugin::errorOccured() not implemented "<< std::endl );
323 void CANSimPlugin::standardFrameReceived(const can_frame& frame)
326 LOG_INFO( "CANSimPlugin::standardFrameReceived() not implemented "<< std::endl );
329 void CANSimPlugin::extendedFrameReceived(const can_frame& frame)
331 LOG_INFO("CANSimPlugin::extendedFrameReceived()");
334 auto it = mappingTable.find(frame.can_id);
335 if( it == mappingTable.end()){
336 LOG_WARNING("can_id not found");
340 std::string source(std::get<0>(it->second));
341 VehicleProperty::Property name(std::get<1>(it->second));
342 Zone::Type zone(std::get<2>(it->second));
343 AbstractPropertyType* value = findPropertyType(name, zone);
347 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(value->toVariant(), &g_variant_unref);
348 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v_untrusted(
349 g_variant_new_from_data( g_variant_get_type(v.release()), frame.data, frame.can_dlc, FALSE, nullptr, nullptr),
352 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v_normal(g_variant_get_normal_form(v_untrusted.release()), &g_variant_unref);
353 if(g_variant_is_normal_form(v_normal.get())) {
354 value->fromVariant(v_normal.get());
355 routingEngine->updateProperty(value, source);
358 LOG_ERROR("Can't convert value from CAN to GVariant");
362 void CANSimPlugin::errorFrameReceived(const can_frame& frame)
364 LOG_INFO("CANSimPlugin::errorFrameReceived()");
368 void CANSimPlugin::remoteTransmissionRequest(const can_frame& frame)
371 LOG_INFO( "CANSimPlugin::remoteTransmissionRequest() not implemented "<< std::endl );
374 void CANSimPlugin::printFrame(const can_frame& frame) const
376 LOG_INFO( "CANSimPlugin::printFrame can_id: " << std::hex << frame.can_id << std::dec << endl );
377 LOG_INFO( "CANSimPlugin::printFrame can_dlc: " << int(frame.can_dlc) << endl );
379 std::stringstream ss;
380 for(int i=0; i<frame.can_dlc; ++i){
381 ss << " " << std::hex << (int)(frame.data[i]);
385 LOG_INFO( "CANSimPlugin::printFrame can data" << ss.str() << endl );