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" AbstractSource* 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 std::unique_ptr< AmbPlugin<CANSimPlugin> > plugin(new AmbPlugin<CANSimPlugin>(routingengine, config));
48 return plugin.release();
51 //----------------------------------------------------------------------------
53 //----------------------------------------------------------------------------
55 const VehicleProperty::Property MappingTable = "MappingTable";
60 const VehicleProperty::Property BatteryStatus = "BatteryStatus";
61 PROPERTYTYPEBASIC(BatteryStatus, uint16_t)
62 const VehicleProperty::Property FullBatteryRange = "FullBatteryRange";
63 PROPERTYTYPEBASIC(FullBatteryRange, uint16_t)
64 const VehicleProperty::Property Weather = "Weather";
65 PROPERTYTYPEBASIC(Weather, uint16_t)
66 const VehicleProperty::Property AvgKW = "AvgKW";
67 PROPERTYTYPEBASIC(AvgKW, double)
69 #define ADDPROPERTY(property, default_value, zone_value) \
70 addPropertySupport(zone_value, [](){ \
71 return new property ## Type(default_value); \
74 CANSimPlugin::CANSimPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
75 AmbPluginImpl(re, config, parent)
77 auto it = config.find("interfaces");
78 if(it != config.end() && it->second.length()){
79 std::unique_ptr<json_object, decltype(&json_object_put)> rootobject(json_tokener_parse(it->second.c_str()), &json_object_put);
81 g_assert(json_object_get_type(rootobject.get())==json_type_array);
82 array_list *ifacelist = json_object_get_array(rootobject.get());
84 for(int i=0; i < array_list_length(ifacelist); ++i)
86 json_object* obj = (json_object*)array_list_get_idx(ifacelist,i);
87 const char* str = obj ? json_object_get_string(obj) : nullptr;
89 interfaces[str] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
95 // Default interface if none has been configured.
96 if(interfaces.empty()){
97 interfaces[DEFAULT_CAN_IF_NAME] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
103 StringPropertyType *s = new StringPropertyType(MappingTable, "");
104 s->zone = Zone::None;
112 ADDPROPERTY(VehicleProperty::ChildLockStatus, false, Zone::None);
113 ADDPROPERTY(VehicleProperty::LightHead, false, Zone::None);
114 ADDPROPERTY(VehicleProperty::LightParking, false, Zone::None);
115 ADDPROPERTY(VehicleProperty::AirConditioning, false, Zone::None);
116 ADDPROPERTY(BatteryStatus, 58, Zone::None);
117 ADDPROPERTY(FullBatteryRange, 350, Zone::None);
118 ADDPROPERTY(VehicleProperty::ExteriorTemperature, 74, Zone::None);
119 ADDPROPERTY(VehicleProperty::InteriorTemperature, 68, Zone::None);
120 ADDPROPERTY(VehicleProperty::FrontWheelRadius, 0, Zone::None);
121 ADDPROPERTY(Weather, 1, Zone::None);
122 ADDPROPERTY(AvgKW, 28, Zone::None);
123 ADDPROPERTY(VehicleProperty::VehicleSpeed, 65, Zone::None);
124 ADDPROPERTY(VehicleProperty::Odometer, 75126, Zone::None);
125 ADDPROPERTY(VehicleProperty::TransmissionShiftPosition, Transmission::Drive, Zone::None);
126 ADDPROPERTY(VehicleProperty::NightMode, false, Zone::None);
127 ADDPROPERTY(VehicleProperty::ExteriorBrightness, 1000, Zone::None);
129 ADDPROPERTY(VehicleProperty::LightHazard, false, Zone::None);
130 ADDPROPERTY(VehicleProperty::SeatHeater, 0, Zone::FrontLeft);
131 ADDPROPERTY(VehicleProperty::SeatHeater, 0, Zone::FrontRight);
132 ADDPROPERTY(VehicleProperty::AirRecirculation, false, Zone::None);
133 ADDPROPERTY(VehicleProperty::AirflowDirection, HVAC::Front, Zone::None);
134 ADDPROPERTY(VehicleProperty::FanSpeed, 200, Zone::None);
135 ADDPROPERTY(VehicleProperty::TargetTemperature, 68, Zone::Left);
136 ADDPROPERTY(VehicleProperty::TargetTemperature, 68, Zone::Right);
138 ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Front);
139 ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Rear);
141 ADDPROPERTY(VehicleProperty::VehiclePowerMode, Power::Run, Zone::None);
143 ADDPROPERTY(VehicleProperty::TirePressure, 2.3, Zone::FrontLeft);
144 ADDPROPERTY(VehicleProperty::TirePressure, 2.3, Zone::FrontRight);
145 ADDPROPERTY(VehicleProperty::TirePressure, 2.4, Zone::RearLeft);
146 ADDPROPERTY(VehicleProperty::TirePressure, 2.4, Zone::RearRight);
149 CANSimPlugin::~CANSimPlugin()
151 for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
156 void CANSimPlugin::init()
158 AmbPluginImpl::init();
159 for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
160 it->second->start(it->first.c_str());
164 void CANSimPlugin::supportedChanged(const PropertyList& supportedProperties)
166 PropertyList s = const_cast<PropertyList&>(supportedProperties);
167 removeOne(&s, MappingTable);// CANSimPlugin has own copy of the PropertyList from AmbPlugin
168 createMappingTable(supportedProperties);
171 int CANSimPlugin::supportedOperations() const
173 return AbstractSource::Get | AbstractSource::Set;
176 void CANSimPlugin::createMappingTable(const PropertyList& /*supported*/)
179 // Local helper classes
181 class JsonObject : public std::unique_ptr<json_object, decltype(&json_object_put)>
184 JsonObject(json_object* object) : std::unique_ptr<json_object, decltype(&json_object_put)>(object, &json_object_put) {}
189 PROPERTY(const VehicleProperty::Property& propertyName, const Zone::Type& z, int canId) :
195 PROPERTY(const PROPERTY& other) = delete;
196 PROPERTY& operator=(const PROPERTY& other) = delete;
197 PROPERTY(PROPERTY&& other) = default;
198 PROPERTY& operator=(PROPERTY&& other) = default;
201 JsonObject prop(json_object_new_object());
202 json_object_object_add(prop.get(), "can_id", json_object_new_int(can_id));
203 json_object_object_add(prop.get(), "name", json_object_new_string(name.c_str()));
204 json_object_object_add(prop.get(), "zone", json_object_new_int(static_cast<int>(zone)));
214 PropertyList allProperties(VehicleProperty::capabilities());
216 removeOne(&allProperties, MappingTable);
219 // Create mapping table in JSON format
221 map< std::string, std::deque<PROPERTY> > table;
222 PropertyList addedProperties;
223 PropertyList removedProperties;
224 std::map< canid_t, std::tuple< std::string, VehicleProperty::Property, Zone::Type> > newMappingTable;
225 int can_id = 10; // Let's have a space for a special messages. Just in case .... in the future.
226 for(PropertyList::const_iterator propIt = allProperties.begin(); propIt != allProperties.end(); ++propIt)
228 VehicleProperty::Property propertyName(*propIt);
230 std::vector<std::string> sources(routingEngine->sourcesForProperty(propertyName));
231 size_t size = sources.size();
233 bool IAmTheSource = contains(sources, uuid());
235 if(size == 0 || size == 1 && IAmTheSource) {
237 // I'm the source from now
238 ZonePropertyType& zonePropType = properties[propertyName];
239 std::shared_ptr<AbstractPropertyType> value(VehicleProperty::getPropertyTypeForPropertyNameValue(propertyName));
241 value->zone = Zone::None;
242 zonePropType.insert(make_pair(Zone::None, value));
243 addedProperties.push_back(propertyName);
246 properties.erase(propertyName);
249 std::string source(uuid());
250 //PropertyInfo info(routingEngine->getPropertyInfo(propertyName,source));
251 //Zone::ZoneList zones(info.zones());
253 Zone::ZoneList zones;
255 for(int i = 0; i< 10; ++i){
256 Zone::Type zone(Zone::None);
258 zone = static_cast<Zone::Type>(1 << i);
259 zones.push_back(zone);
261 zones.push_back(Zone::FrontRight);
262 zones.push_back(Zone::FrontLeft);
263 zones.push_back(Zone::MiddleRight);
264 zones.push_back(Zone::MiddleLeft);
265 zones.push_back(Zone::RearRight);
266 zones.push_back(Zone::RearLeft);
268 for( auto z=zones.begin(); z != zones.end(); ++z ){
269 table[source].push_back(PROPERTY(propertyName, *z, can_id));
270 newMappingTable[can_id++] = make_tuple(source, propertyName, *z);
273 else if(IAmTheSource){
274 // I'm the source, and there is another source
275 properties.erase(propertyName);// I don't need to simulate it anymore
276 removedProperties.push_back(propertyName);
280 if(addedProperties.size() || removedProperties.size()) {
281 JsonObject sources(json_object_new_array());
282 for(auto it = table.begin(); it != table.end(); ++it) {
283 // one source object:
284 JsonObject source(json_object_new_object());
285 JsonObject description(json_object_new_object());
286 json_object_object_add(description.get(), "guid", json_object_new_string(it->first.c_str()));
287 json_object_object_add(source.get(), "source", description.release());
289 JsonObject sigs(json_object_new_array());
290 for(auto signalIt = it->second.begin(); signalIt != it->second.end(); ++signalIt) {
291 json_object_array_add(sigs.get(), signalIt->toJson().release());
293 // add signals into source
294 json_object_object_add(source.get(), "signals", sigs.release());
295 // add one source into sources array
296 json_object_array_add(sources.get(), source.release());
299 JsonObject result(json_object_new_object());
300 json_object_object_add(result.get(), "sources", sources.release());
302 std::string mappingTableValue(json_object_to_json_string(result.get()));
304 std::replace(mappingTableValue.begin(), mappingTableValue.end(), '"', '\'');// replace all " to '
305 auto tableProperty = properties[MappingTable][Zone::None];
307 // we have a new MappingTable
308 mappingTable.swap(newMappingTable);
309 tableProperty->setValue(mappingTableValue);
310 routingEngine->updateProperty(tableProperty.get(), uuid());
313 routingEngine->updateSupported(addedProperties, removedProperties, &source);
318 void CANSimPlugin::errorOccured(CANObserver::CANError error)
321 LOG_INFO( "CANSimPlugin::errorOccured() not implemented "<< std::endl );
324 void CANSimPlugin::standardFrameReceived(const can_frame& frame)
327 LOG_INFO( "CANSimPlugin::standardFrameReceived() not implemented "<< std::endl );
330 void CANSimPlugin::extendedFrameReceived(const can_frame& frame)
332 LOG_INFO("CANSimPlugin::extendedFrameReceived()");
335 auto it = mappingTable.find(frame.can_id);
336 if( it == mappingTable.end()){
337 LOG_WARNING("can_id not found");
341 std::string source(std::get<0>(it->second));
342 VehicleProperty::Property name(std::get<1>(it->second));
343 Zone::Type zone(std::get<2>(it->second));
344 AbstractPropertyType* value = findPropertyType(name, zone);
348 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(value->toVariant(), &g_variant_unref);
349 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v_untrusted(
350 g_variant_new_from_data( g_variant_get_type(v.release()), frame.data, frame.can_dlc, FALSE, nullptr, nullptr),
353 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v_normal(g_variant_get_normal_form(v_untrusted.release()), &g_variant_unref);
354 if(g_variant_is_normal_form(v_normal.get())) {
355 value->fromVariant(v_normal.get());
356 routingEngine->updateProperty(value, source);
359 LOG_ERROR("Can't convert value from CAN to GVariant");
363 void CANSimPlugin::errorFrameReceived(const can_frame& frame)
365 LOG_INFO("CANSimPlugin::errorFrameReceived()");
369 void CANSimPlugin::remoteTransmissionRequest(const can_frame& frame)
372 LOG_INFO( "CANSimPlugin::remoteTransmissionRequest() not implemented "<< std::endl );
375 void CANSimPlugin::printFrame(const can_frame& frame) const
377 LOG_INFO( "CANSimPlugin::printFrame can_id: " << std::hex << frame.can_id << std::dec << endl );
378 LOG_INFO( "CANSimPlugin::printFrame can_dlc: " << int(frame.can_dlc) << endl );
380 std::stringstream ss;
381 for(int i=0; i<frame.can_dlc; ++i){
382 ss << " " << std::hex << (int)(frame.data[i]);
386 LOG_INFO( "CANSimPlugin::printFrame can data" << ss.str() << endl );