319104a6eb6e4f7d0da0239be33da08b24934bd2
[profile/ivi/automotive-message-broker.git] / plugins / cansimplugin / cansimplugin.cpp
1 /*
2 Copyright (C) 2012 Intel Corporation
3
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.
8
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.
13
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
17 */
18
19 #include <boost/assert.hpp>
20 #include <glib.h>
21 #include <deque>
22
23 #include <vehicleproperty.h>
24 #include <listplusplus.h>
25
26 #include <logger.h>
27 #include <ambplugin.h>
28
29 #include "cansimplugin.h"
30
31 static const char* DEFAULT_CAN_IF_NAME = "vcan0";
32
33 //----------------------------------------------------------------------------
34 // CANSimPlugin
35 //----------------------------------------------------------------------------
36
37 // library exported function for plugin loader
38 extern "C" AbstractSource* create(AbstractRoutingEngine* routingengine, std::map<std::string, std::string> config)
39 {
40 #ifndef UNIT_TESTS
41         DEBUG_CONF("cansimplugin",
42                 CUtil::Logger::file_off|CUtil::Logger::screen_on,
43                 CUtil::Logger::EInfo, CUtil::Logger::EInfo
44         );
45 #endif
46         std::unique_ptr< AmbPlugin<CANSimPlugin> > plugin(new AmbPlugin<CANSimPlugin>(routingengine, config));
47         plugin->init();
48         return plugin.release();
49 }
50
51 //----------------------------------------------------------------------------
52 // CANSimPlugin
53 //----------------------------------------------------------------------------
54
55 const VehicleProperty::Property MappingTable = "MappingTable";
56
57 //
58 // IVIPOC signals
59 //
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)
68
69 #define ADDPROPERTY(property, default_value, zone_value) \
70                         addPropertySupport(zone_value, [](){ \
71                                 return new property ## Type(default_value); \
72                         })
73
74 CANSimPlugin::CANSimPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
75         AmbPluginImpl(re, config, parent)
76 {
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);
80                 if(rootobject){
81                         g_assert(json_object_get_type(rootobject.get())==json_type_array);
82                         array_list *ifacelist = json_object_get_array(rootobject.get());
83                         if (ifacelist) {
84                                 for(int i=0; i < array_list_length(ifacelist); ++i)
85                                 {
86                                         json_object* obj = (json_object*)array_list_get_idx(ifacelist,i);
87                                         const char* str = obj ? json_object_get_string(obj) : nullptr;
88                                         if(str){
89                                                 interfaces[str] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this)));
90                                         }
91                                 }
92                         }
93                 }
94         }
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)));
98         }
99
100         addPropertySupport(
101                 Zone::None,
102                 [](){
103                         StringPropertyType *s = new StringPropertyType(MappingTable, "");
104                         s->zone = Zone::None;
105                         return s;
106                 }
107         );
108
109         //
110         // IVIPOC signals
111         //
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);
128         // HVAC
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);
137
138         ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Front);
139         ADDPROPERTY(VehicleProperty::Defrost, false, Zone::Rear);
140
141         ADDPROPERTY(VehicleProperty::VehiclePowerMode, Power::Run, Zone::None);
142         // TirePresure
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);
147 }
148
149 CANSimPlugin::~CANSimPlugin()
150 {
151         for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
152                 it->second->stop();
153         }
154 }
155
156 void CANSimPlugin::init()
157 {
158         AmbPluginImpl::init();
159         for(auto it = interfaces.begin(); it != interfaces.end(); ++it){
160                 it->second->start(it->first.c_str());
161         }
162 }
163
164 void CANSimPlugin::supportedChanged(const PropertyList& supportedProperties)
165 {
166         PropertyList s = const_cast<PropertyList&>(supportedProperties);
167         removeOne(&s, MappingTable);// CANSimPlugin has own copy of the PropertyList from AmbPlugin
168         createMappingTable(supportedProperties);
169 }
170
171 int CANSimPlugin::supportedOperations() const
172 {
173         return AbstractSource::Get | AbstractSource::Set;
174 }
175
176 void CANSimPlugin::createMappingTable(const PropertyList& /*supported*/)
177 {
178         //
179         // Local helper classes
180         //
181         class JsonObject : public std::unique_ptr<json_object, decltype(&json_object_put)>
182         {
183         public:
184                 JsonObject(json_object* object) : std::unique_ptr<json_object, decltype(&json_object_put)>(object, &json_object_put) {}
185         };
186
187         class PROPERTY{
188         public:
189                 PROPERTY(const VehicleProperty::Property& propertyName, const Zone::Type& z, int canId) :
190                         name(propertyName),
191                         zone(z),
192                         can_id(canId)
193                 {
194                 }
195                 PROPERTY(const PROPERTY& other) = delete;
196                 PROPERTY& operator=(const PROPERTY& other) = delete;
197                 PROPERTY(PROPERTY&& other) = default;
198                 PROPERTY& operator=(PROPERTY&& other) = default;
199                 JsonObject toJson()
200                 {
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)));
205                         return prop;
206                 }
207         private:
208                 std::string name;
209                 Zone::Type zone;
210                 int can_id;
211         };
212
213         //
214         PropertyList allProperties(VehicleProperty::capabilities());
215
216         removeOne(&allProperties, MappingTable);
217
218         //
219         // Create mapping table in JSON format
220         //
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)
227         {
228                 VehicleProperty::Property propertyName(*propIt);
229
230                 std::vector<std::string> sources(routingEngine->sourcesForProperty(propertyName));
231                 size_t size = sources.size();
232
233                 bool IAmTheSource = contains(sources, uuid());
234
235                 if(size == 0 || size == 1 && IAmTheSource) {
236                         if( size == 0 ){
237                                 // I'm the source from now
238                                 ZonePropertyType& zonePropType = properties[propertyName];
239                                 std::shared_ptr<AbstractPropertyType> value(VehicleProperty::getPropertyTypeForPropertyNameValue(propertyName));
240                                 if(value){
241                                         value->zone = Zone::None;
242                                         zonePropType.insert(make_pair(Zone::None, value));
243                                         addedProperties.push_back(propertyName);
244                                 }
245                                 else{
246                                         properties.erase(propertyName);
247                                 }
248                         }
249                         std::string source(uuid());
250                         //PropertyInfo info(routingEngine->getPropertyInfo(propertyName,source));
251                         //Zone::ZoneList zones(info.zones());
252                         //if(zones.empty())
253                         Zone::ZoneList zones;
254                         {
255                                 for(int i = 0; i< 10; ++i){
256                                         Zone::Type zone(Zone::None);
257                                         if(i)
258                                                 zone = static_cast<Zone::Type>(1 << i);
259                                         zones.push_back(zone);
260                                 }
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);
267                         }
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);
271                         }
272                 }
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);
277                 }
278         }
279
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());
288                         // signals:
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());
292                         }
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());
297                 }
298                 // result json:
299                 JsonObject result(json_object_new_object());
300                 json_object_object_add(result.get(), "sources", sources.release());
301
302                 std::string mappingTableValue(json_object_to_json_string(result.get()));
303
304                 std::replace(mappingTableValue.begin(), mappingTableValue.end(), '"', '\'');// replace all " to '
305                 auto tableProperty = properties[MappingTable][Zone::None];
306                 if(tableProperty){
307                         // we have a new MappingTable
308                         mappingTable.swap(newMappingTable);
309                         tableProperty->setValue(mappingTableValue);
310                         routingEngine->updateProperty(tableProperty.get(), uuid());
311                 }
312
313                 routingEngine->updateSupported(addedProperties, removedProperties, &source);
314         }
315 }
316
317 // from CANObserver
318 void CANSimPlugin::errorOccured(CANObserver::CANError error)
319 {
320         (void) error;
321         LOG_INFO( "CANSimPlugin::errorOccured() not implemented "<< std::endl );
322 }
323
324 void CANSimPlugin::standardFrameReceived(const can_frame& frame)
325 {
326         (void) frame;
327         LOG_INFO( "CANSimPlugin::standardFrameReceived() not implemented "<< std::endl );
328 }
329
330 void CANSimPlugin::extendedFrameReceived(const can_frame& frame)
331 {
332         LOG_INFO("CANSimPlugin::extendedFrameReceived()");
333         printFrame(frame);
334
335         auto it = mappingTable.find(frame.can_id);
336         if( it == mappingTable.end()){
337                 LOG_WARNING("can_id not found");
338                 return;
339         }
340
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);
345         if(!value)
346                 return;
347
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),
351                 &g_variant_unref
352         );
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);
357         }
358         else{
359                 LOG_ERROR("Can't convert value from CAN to GVariant");
360         }
361 }
362
363 void CANSimPlugin::errorFrameReceived(const can_frame& frame)
364 {
365         LOG_INFO("CANSimPlugin::errorFrameReceived()");
366         printFrame(frame);
367 }
368
369 void CANSimPlugin::remoteTransmissionRequest(const can_frame& frame)
370 {
371         (void) frame;
372         LOG_INFO( "CANSimPlugin::remoteTransmissionRequest() not implemented "<< std::endl );
373 }
374
375 void CANSimPlugin::printFrame(const can_frame& frame) const
376 {
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 );
379
380         std::stringstream ss;
381         for(int i=0; i<frame.can_dlc; ++i){
382                 ss << " " << std::hex << (int)(frame.data[i]);
383         }
384         ss << std::dec;
385
386         LOG_INFO( "CANSimPlugin::printFrame can data" << ss.str() << endl );
387 }
388
389