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 "murphysource.h"
22 #include <boost/assert.hpp>
23 #include <boost/lexical_cast.hpp>
26 #include <listplusplus.h>
27 #include <timestamp.h>
29 #include <murphy/common.h>
32 #include <murphy/qt/qt-glue.h>
35 #include <murphy/glib/glib-glue.h>
38 // #include <vehicleproperty.h>
39 // #include <abstractpropertytype.h>
44 void MurphySource::processValue(string propertyName, AbstractPropertyType *prop)
46 if (murphyProperties.find(propertyName) != murphyProperties.end()) {
47 delete murphyProperties[propertyName];
48 murphyProperties[propertyName] = prop;
51 murphyProperties[propertyName] = prop;
52 m_re->updateSupported(supported(), PropertyList(), this);
55 // cout << "updating property!" << endl;
56 m_re->updateProperty(propertyName, prop, uuid());
59 bool MurphySource::hasProperty(string propertyName)
61 PropertyList props = supported();
62 return ListPlusPlus<VehicleProperty::Property>(&props).contains(propertyName);
65 static void recvfrom_msg(mrp_transport_t *transp, mrp_msg_t *msg,
66 mrp_sockaddr_t *addr, socklen_t addrlen,
69 MurphySource *s = (MurphySource *) user_data;
74 mrp_msg_value_t value;
79 DebugOut()<<"Received a message from Murphy!"<<endl;
81 if (!mrp_msg_iterate(msg, &cursor, &tag, &type, &value, &size))
84 if (tag == 1 && type == MRP_MSG_FIELD_STRING)
85 property_name = value.str;
87 string dstr(property_name);
89 if (!mrp_msg_iterate(msg, &cursor, &tag, &type, &value, &size))
95 DebugOut() << "Property '" << property_name << "' with value: " <<endl;
98 case MRP_MSG_FIELD_STRING:
100 StringPropertyType *prop = new StringPropertyType(dstr,value.str);
102 if (!s->hasProperty(dstr)) {
103 VehicleProperty::registerProperty(dstr,
104 [dstr](){return new StringPropertyType(dstr,"");});
107 DebugOut() << "string:" << value.str << std::endl;
108 s->processValue(property_name, prop);
111 case MRP_MSG_FIELD_DOUBLE:
113 BasicPropertyType<double> *prop =
114 new BasicPropertyType<double>(dstr,value.dbl);
116 if (!s->hasProperty(dstr)) {
117 VehicleProperty::registerProperty(dstr,
118 [dstr](){return new BasicPropertyType<double>(dstr,0);});
121 DebugOut() << "double:" << value.dbl << std::endl;
122 s->processValue(property_name, prop);
125 case MRP_MSG_FIELD_BOOL:
127 BasicPropertyType<bool> *prop =
128 new BasicPropertyType<bool>(dstr,value.bln);
130 if (!s->hasProperty(dstr)) {
131 VehicleProperty::registerProperty(dstr,
132 [dstr](){return new BasicPropertyType<bool>(dstr,FALSE);});
135 DebugOut() << "boolean:" << value.bln << std::endl;
136 s->processValue(property_name, prop);
139 case MRP_MSG_FIELD_UINT32:
141 BasicPropertyType<uint32_t> *prop =
142 new BasicPropertyType<uint32_t>(dstr,value.u32);
144 if (!s->hasProperty(dstr)) {
145 VehicleProperty::registerProperty(dstr,
146 [dstr](){return new BasicPropertyType<uint32_t>(dstr,0);});
149 DebugOut() << "uint32:" << value.u32 << std::endl;
150 s->processValue(property_name, prop);
153 case MRP_MSG_FIELD_UINT16:
155 BasicPropertyType<uint16_t> *prop =
156 new BasicPropertyType<uint16_t>(dstr,value.u16);
158 if (!s->hasProperty(dstr)) {
159 VehicleProperty::registerProperty(dstr,
160 [dstr](){return new BasicPropertyType<uint16_t>(dstr,0);});
163 DebugOut() << "uint16:" << value.u16 << std::endl;
164 s->processValue(property_name, prop);
167 case MRP_MSG_FIELD_INT32:
169 BasicPropertyType<int32_t> *prop =
170 new BasicPropertyType<int32_t>(dstr, value.s32);
172 if (!s->hasProperty(dstr)) {
173 VehicleProperty::registerProperty(dstr,
174 [dstr](){return new BasicPropertyType<int32_t>(dstr,0);});
177 DebugOut() << "int32:" << value.s32 << std::endl;
178 s->processValue(property_name, prop);
181 case MRP_MSG_FIELD_INT16:
183 BasicPropertyType<int16_t> *prop =
184 new BasicPropertyType<int16_t>(dstr, value.s16);
186 if (!s->hasProperty(dstr)) {
187 VehicleProperty::registerProperty(dstr,
188 [dstr](){return new BasicPropertyType<int16_t>(dstr, 0);});
191 DebugOut() << "int16:" << value.s16 << std::endl;
192 s->processValue(property_name, prop);
196 case MRP_MSG_FIELD_UINT8:
198 BasicPropertyType<uint8_t> prop =
199 BasicPropertyType<uint8_t>(value.u8);
200 std::cout << "byte:" << value.u8 << std::endl;
201 s->processValue(property_name, &prop);
206 DebugOut()<<"Unknown type"<<endl;
210 static void recv_msg(mrp_transport_t *transp, mrp_msg_t *msg, void *user_data)
212 return recvfrom_msg(transp, msg, NULL, 0, user_data);
215 static void closed_evt(mrp_transport_t *t, int error, void *user_data)
217 /* TODO: should process the error somehow */
219 MurphySource *s = (MurphySource *) user_data;
221 s->setState(MRP_PROCESS_STATE_NOT_READY);
222 s->setConnected(FALSE);
226 void MurphySource::setConnected(bool connected)
228 m_connected = connected;
232 int MurphySource::connectToMurphy()
236 int flags = MRP_TRANSPORT_REUSEADDR | MRP_TRANSPORT_MODE_MSG;
237 static mrp_transport_evt_t evt;
240 evt.recvmsg = recv_msg;
241 evt.recvmsgfrom = recvfrom_msg;
242 evt.closed = closed_evt;
244 if (m_ml == NULL || m_address.empty())
247 if (m_connected == TRUE)
250 alen = mrp_transport_resolve(NULL, m_address.c_str(), &addr, sizeof(addr), &atype);
253 debugOut("Failed to resolve address");
257 m_tport = mrp_transport_create(m_ml, atype, &evt, this, flags);
260 debugOut("Can't create a Murphy transport");
264 if (mrp_transport_connect(m_tport, &addr, alen) == 0) {
265 mrp_transport_destroy(m_tport);
267 debugOut("Failed to connect to Murphy");
277 MurphySource::MurphySource(AbstractRoutingEngine *re, map<string, string> config) : AbstractSource(re, config)
283 // main loop integration
286 m_ml = mrp_mainloop_qt_get();
287 debugOut("Murphy plugin initialized using QT mainloop!");
289 GMainLoop *g_ml = g_main_loop_new(NULL, TRUE);
290 m_ml = mrp_mainloop_glib_get(g_ml);
291 debugOut("Murphy plugin initialized using glib mainloop!");
294 setConfiguration(config);
297 MurphySource::~MurphySource()
299 mrp_process_set_state("ambd", MRP_PROCESS_STATE_NOT_READY);
300 mrp_transport_destroy(m_tport);
301 mrp_mainloop_unregister(m_ml);
303 map<string, AbstractPropertyType *>::iterator i;
305 for (i = murphyProperties.begin(); i != murphyProperties.end(); i++) {
306 // TODO: unregister VehicleProperty (*i).first
312 void MurphySource::setState(mrp_process_state_t state)
317 mrp_process_state_t MurphySource::getState()
322 static void murphy_watch(const char *id, mrp_process_state_t state, void *user_data)
324 MurphySource *s = (MurphySource *) user_data;
326 debugOut("murphy process watch event");
328 if (strcmp(id, "murphy-amb") != 0)
331 printf("murphyd state changed to %s\n",
332 state == MRP_PROCESS_STATE_READY ? "ready" : "not ready");
334 if (state == MRP_PROCESS_STATE_NOT_READY &&
335 s->getState() == MRP_PROCESS_STATE_READY) {
336 DebugOut()<<"lost connection to murphyd"<<endl;
339 else if (state == MRP_PROCESS_STATE_READY) {
340 /* start connecting if needed */
341 s->connectToMurphy();
347 void MurphySource::readyToConnect(mrp_mainloop_t *ml)
349 /* set a watch to follow Murphy status */
351 if (mrp_process_set_watch("murphy-amb", ml, murphy_watch, this) < 0) {
352 DebugOut()<<"failed to set a murphy process watch"<<endl;
356 mrp_process_set_state("ambd", MRP_PROCESS_STATE_READY);
358 /* check if Murphy is running */
359 m_state = mrp_process_query_state("murphy-amb");
361 if (m_state == MRP_PROCESS_STATE_READY)
366 void MurphySource::setConfiguration(map<string, string> config)
370 for (map<string,string>::iterator i=configuration.begin();i!=configuration.end();i++) {
371 if ((*i).first == "address") {
372 address = (*i).second;
373 // cout << "address: " << address << endl;
375 // TODO: sanity check
380 // TODO: read supported values from configuration?
381 m_re->updateSupported(supported(), PropertyList(), this);
383 // set up the connection with Murphy
384 if (!m_address.empty())
385 readyToConnect(m_ml);
389 PropertyList MurphySource::supported()
391 // debugOut("> supported");
393 PropertyList properties;
394 map<string, AbstractPropertyType *>::iterator i;
396 for (i = murphyProperties.begin(); i != murphyProperties.end(); i++) {
397 properties.push_back((*i).first);
404 int MurphySource::supportedOperations()
406 // debugOut("> supportedOperations");
407 return Get; // | Set;
408 //we really don't support Set
412 void MurphySource::subscribeToPropertyChanges(VehicleProperty::Property property)
414 // debugOut("> subscribeToPropertyChanges");
418 void MurphySource::unsubscribeToPropertyChanges(VehicleProperty::Property property)
420 // debugOut("> unsubscribeToPropertyChanges");
424 void MurphySource::getPropertyAsync(AsyncPropertyReply *reply)
426 // debugOut("> getPropertyAsync");
428 if (murphyProperties.find(reply->property) != murphyProperties.end()) {
429 AbstractPropertyType *prop = murphyProperties[reply->property];
431 reply->success = true;
432 reply->completed(reply);
437 void MurphySource::getRangePropertyAsync(AsyncRangePropertyReply *reply)
439 // debugOut("> getRangePropertyAsync");
443 AsyncPropertyReply *MurphySource::setProperty(AsyncSetPropertyRequest request)
445 // debugOut("> setProperty");
447 processValue(request.property, request.value);
449 AsyncPropertyReply* reply = new AsyncPropertyReply(request);
450 reply->success = true;
451 reply->completed(reply);
456 extern "C" AbstractSource *create(AbstractRoutingEngine* routingengine, map<string, string> config)
458 return new MurphySource(routingengine, config);