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