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