reverted varianttype
[profile/ivi/automotive-message-broker.git] / plugins / murphyplugin / murphysource.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 "murphysource.h"
20
21 #include <iostream>
22 #include <boost/assert.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <glib.h>
25 #include <sstream>
26 #include <listplusplus.h>
27 #include <timestamp.h>
28
29 #include <murphy/common.h>
30 #include <murphy/glib/glib-glue.h>
31
32 #include "debugout.h"
33
34 void MurphySource::processValue(string propertyName, AbstractPropertyType *prop)
35 {
36         if (murphyProperties.find(propertyName) != murphyProperties.end())
37         {
38                 delete murphyProperties[propertyName];
39                 murphyProperties[propertyName] = prop;
40         }
41         else
42         {
43                 murphyProperties[propertyName] = prop;
44                 m_re->updateSupported(supported(), PropertyList(), this);
45         }
46
47         m_re->updateProperty(prop, uuid());
48 }
49
50 bool MurphySource::hasProperty(string propertyName)
51 {
52         PropertyList props = supported();
53         return contains(props,propertyName);
54 }
55
56 static void recvfrom_msg(mrp_transport_t *transp, mrp_msg_t *msg,
57                                                  mrp_sockaddr_t *addr, socklen_t addrlen,
58                                                  void *user_data)
59 {
60         MurphySource *s = (MurphySource *) user_data;
61
62         void *cursor = NULL;
63         uint16_t tag = 0;
64         uint16_t type = 0;
65         mrp_msg_value_t value;
66         size_t size;
67
68         std::string property_name;
69
70         DebugOut()<<"Received a message from Murphy!"<<endl;
71
72         if (!mrp_msg_iterate(msg, &cursor, &tag, &type, &value, &size))
73                 return;
74
75         if (tag == 1 && type == MRP_MSG_FIELD_STRING)
76                 property_name = value.str;
77
78         if (!mrp_msg_iterate(msg, &cursor, &tag, &type, &value, &size))
79                 return;
80
81         if (tag != 2)
82                 return;
83
84         DebugOut() << "Property '" << property_name << "' with value: " <<endl;
85
86         bool hasProp = contains(VehicleProperty::capabilities(), property_name);
87
88         stringstream val;
89
90         switch (type)
91         {
92                 case MRP_MSG_FIELD_STRING:
93                 {
94                         val << value.str;
95                         if (!hasProp)
96                         {
97                                 VehicleProperty::registerProperty(property_name,
98                                                                                                   [property_name](){return new StringPropertyType(property_name, "");});
99                         }
100
101                         DebugOut() << "string:" << value.str << std::endl;
102                         break;
103                 }
104                 case MRP_MSG_FIELD_DOUBLE:
105                 {
106                         val << value.dbl;
107
108                         if (!hasProp)
109                         {
110                                 VehicleProperty::registerProperty(property_name,
111                                                                                                   [property_name](){return new BasicPropertyType<double>(property_name, 0);});
112                         }
113
114                         DebugOut() << "double:" << value.dbl << std::endl;
115                         break;
116                 }
117                 case MRP_MSG_FIELD_BOOL:
118                 {
119                         val << value.bln;
120
121                         if (!hasProp)
122                         {
123                                 VehicleProperty::registerProperty(property_name,
124                                                                                                   [property_name](){return new BasicPropertyType<bool>(property_name, FALSE);});
125                         }
126
127                         DebugOut() << "boolean:" << value.bln << std::endl;
128                         break;
129                 }
130                 case MRP_MSG_FIELD_UINT32:
131                 {
132                         val << value.u32;
133
134                         if (!hasProp)
135                         {
136                                 VehicleProperty::registerProperty(property_name,
137                                                                                                   [property_name](){return new BasicPropertyType<uint32_t>(property_name, 0);});
138                         }
139
140                         DebugOut() << "uint32:" << value.u32 << std::endl;
141                         break;
142                 }
143                 case MRP_MSG_FIELD_UINT16:
144                 {
145                         val << value.u16;
146
147                         if (!hasProp)
148                         {
149                                 VehicleProperty::registerProperty(property_name,
150                                                                                                   [property_name](){return new BasicPropertyType<uint16_t>(property_name, 0);});
151                         }
152
153                         DebugOut() << "uint16:" << value.u16 << std::endl;
154
155                         break;
156                 }
157                 case MRP_MSG_FIELD_INT32:
158                 {
159                         val << value.s32;
160
161                         if (!hasProp)
162                         {
163                                 VehicleProperty::registerProperty(property_name,
164                                                                                                   [property_name](){return new BasicPropertyType<int32_t>(property_name, 0);});
165                         }
166
167                         DebugOut() << "int32:" << value.s32 << std::endl;
168                         break;
169                 }
170                 case MRP_MSG_FIELD_INT16:
171                 {
172                         val << value.s16;
173
174                         if (!hasProp)
175                         {
176                                 VehicleProperty::registerProperty(property_name,
177                                                                                                   [property_name](){return new BasicPropertyType<int16_t>(property_name, 0);});
178                         }
179
180                         DebugOut() << "int16:" << value.s16 << std::endl;
181                         break;
182                 }
183                 default:
184                         DebugOut()<<"Unknown type"<<endl;
185         }
186
187         AbstractPropertyType* prop = VehicleProperty::getPropertyTypeForPropertyNameValue(property_name);
188
189         prop->fromString(val.str());
190         s->processValue(property_name, prop);
191 }
192
193 static void recv_msg(mrp_transport_t *transp, mrp_msg_t *msg, void *user_data)
194 {
195         return recvfrom_msg(transp, msg, NULL, 0, user_data);
196 }
197
198 static void closed_evt(mrp_transport_t *t, int error, void *user_data)
199 {
200    /* TODO: should process the error somehow */
201
202         MurphySource *s = (MurphySource *) user_data;
203
204         s->setState(MRP_PROCESS_STATE_NOT_READY);
205         s->setConnected(FALSE);
206 }
207
208
209 void MurphySource::setConnected(bool connected)
210 {
211         m_connected = connected;
212 }
213
214
215 int MurphySource::connectToMurphy()
216 {
217         mrp_sockaddr_t addr;
218         socklen_t alen;
219         int flags = MRP_TRANSPORT_REUSEADDR | MRP_TRANSPORT_MODE_MSG;
220         static mrp_transport_evt_t evt;
221         const char *atype;
222
223         evt.recvmsg = recv_msg;
224         evt.recvmsgfrom = recvfrom_msg;
225         evt.closed = closed_evt;
226
227         if (m_ml == NULL || m_address.empty())
228                 return -1;
229
230         if (m_connected == TRUE)
231                 return -1;
232
233         alen = mrp_transport_resolve(NULL, m_address.c_str(), &addr, sizeof(addr), &atype);
234
235         if (alen <= 0)
236         {
237                 debugOut("Failed to resolve address");
238                 return -1;
239         }
240
241         m_tport = mrp_transport_create(m_ml, atype, &evt, this, flags);
242
243         if (!m_tport)
244         {
245                 debugOut("Can't create a Murphy transport");
246                 return -1;
247         }
248
249         if (mrp_transport_connect(m_tport, &addr, alen) == 0)
250         {
251                 mrp_transport_destroy(m_tport);
252                 m_tport = NULL;
253                 debugOut("Failed to connect to Murphy");
254                 return -1;
255         }
256
257         setConnected(true);
258
259         return 0;
260 }
261
262 PropertyInfo MurphySource::getPropertyInfo(const VehicleProperty::Property &property)
263 {
264         Zone::ZoneList zones;
265         zones.push_back(murphyProperties[property]->zone);
266
267         return PropertyInfo(0, zones);
268 }
269
270
271 MurphySource::MurphySource(AbstractRoutingEngine *re, map<string, string> config) : AbstractSource(re, config)
272 {
273         m_source = this;
274         m_re = re;
275         m_connected = false;
276
277         // main loop integration
278
279 /*#ifdef USE_QT_CORE
280         m_ml = mrp_mainloop_qt_get();
281         debugOut("Murphy plugin initialized using QT mainloop!");
282 #else*/
283         GMainLoop *g_ml = g_main_loop_new(NULL, TRUE);
284         m_ml = mrp_mainloop_glib_get(g_ml);
285         debugOut("Murphy plugin initialized using glib mainloop!");
286 //#endif
287
288         setConfiguration(config);
289 }
290
291 MurphySource::~MurphySource()
292 {
293         mrp_process_set_state("ambd", MRP_PROCESS_STATE_NOT_READY);
294         mrp_transport_destroy(m_tport);
295         mrp_mainloop_unregister(m_ml);
296
297         map<string, AbstractPropertyType *>::iterator i;
298
299         for (i = murphyProperties.begin(); i != murphyProperties.end(); i++)
300         {
301                 // TODO: unregister VehicleProperty (*i).first
302
303                 delete (*i).second;
304         }
305 }
306
307 void MurphySource::setState(mrp_process_state_t state)
308 {
309         m_state = state;
310 }
311
312 mrp_process_state_t MurphySource::getState()
313 {
314         return m_state;
315 }
316
317 static void murphy_watch(const char *id, mrp_process_state_t state, void *user_data)
318 {
319         MurphySource *s = (MurphySource *) user_data;
320
321         debugOut("murphy process watch event");
322
323         if (strcmp(id, "murphy-amb") != 0)
324                 return;
325
326         printf("murphyd state changed to %s\n",
327                         state == MRP_PROCESS_STATE_READY ? "ready" : "not ready");
328
329         if (state == MRP_PROCESS_STATE_NOT_READY &&
330                         s->getState() == MRP_PROCESS_STATE_READY)
331         {
332                 DebugOut()<<"lost connection to murphyd"<<endl;
333         }
334
335         else if (state == MRP_PROCESS_STATE_READY)
336         {
337                 /* start connecting if needed */
338                 s->connectToMurphy();
339         }
340
341         s->setState(state);
342 }
343
344 void MurphySource::readyToConnect(mrp_mainloop_t *ml)
345 {
346         /* set a watch to follow Murphy status */
347
348         if (mrp_process_set_watch("murphy-amb", ml, murphy_watch, this) < 0)
349         {
350                 DebugOut()<<"failed to set a murphy process watch"<<endl;
351                 return;
352         }
353
354         mrp_process_set_state("ambd", MRP_PROCESS_STATE_READY);
355
356         /* check if Murphy is running */
357         m_state = mrp_process_query_state("murphy-amb");
358
359         if (m_state == MRP_PROCESS_STATE_READY)
360                 connectToMurphy();
361 }
362
363
364 void MurphySource::setConfiguration(map<string, string> config)
365 {
366         string address;
367
368         for (map<string,string>::iterator i=configuration.begin();i!=configuration.end();i++)
369         {
370                 if ((*i).first == "address")
371                 {
372                         address = (*i).second;
373                         // cout << "address: " << address << endl;
374
375                         // TODO: sanity check
376                         m_address = address;
377                 }
378         }
379
380         // TODO: read supported values from configuration?
381         m_re->updateSupported(supported(), PropertyList(), this);
382
383         // set up the connection with Murphy
384         if (!m_address.empty())
385                 readyToConnect(m_ml);
386 }
387
388
389 PropertyList MurphySource::supported()
390 {
391         // debugOut("> supported");
392
393         PropertyList properties;
394         map<string, AbstractPropertyType *>::iterator i;
395
396         for (i = murphyProperties.begin(); i != murphyProperties.end(); i++)
397         {
398                 properties.push_back((*i).first);
399         }
400
401         return properties;
402 }
403
404
405 int MurphySource::supportedOperations()
406 {
407         // debugOut("> supportedOperations");
408         return Get; // | Set;
409         //we really don't support Set
410 }
411
412
413 void MurphySource::subscribeToPropertyChanges(VehicleProperty::Property property)
414 {
415         // debugOut("> subscribeToPropertyChanges");
416 }
417
418
419 void MurphySource::unsubscribeToPropertyChanges(VehicleProperty::Property property)
420 {
421         // debugOut("> unsubscribeToPropertyChanges");
422 }
423
424
425 void MurphySource::getPropertyAsync(AsyncPropertyReply *reply)
426 {
427         // debugOut("> getPropertyAsync");
428
429         if (murphyProperties.find(reply->property) != murphyProperties.end())
430         {
431                 AbstractPropertyType *prop = murphyProperties[reply->property];
432                 reply->value = prop;
433                 reply->success = true;
434                 reply->completed(reply);
435         }
436 }
437
438
439 void MurphySource::getRangePropertyAsync(AsyncRangePropertyReply *reply)
440 {
441         // debugOut("> getRangePropertyAsync");
442 }
443
444
445 AsyncPropertyReply *MurphySource::setProperty(AsyncSetPropertyRequest request)
446 {
447         // debugOut("> setProperty");
448
449         processValue(request.property, request.value);
450
451         AsyncPropertyReply* reply = new AsyncPropertyReply(request);
452         reply->success = true;
453         reply->completed(reply);
454         return reply;
455 }
456
457 #if 1
458 extern "C" void create(AbstractRoutingEngine* routingengine, map<string, string> config)
459 {
460         new MurphySource(routingengine, config);
461 }
462 #endif