163cde0ed28a488439ab7c53246c72097544d463
[profile/ivi/automotive-message-broker.git] / plugins / cangenplugin / cangenplugin.h
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 #ifndef _CANGENPLUGINIMPL_H_
20 #define _CANGENPLUGINIMPL_H_
21
22 #include <map>
23 #include <memory>
24 #include <tgmath.h>
25 #include <libwebsockets.h>
26 #include <json.h>
27
28 #include <canbus.h>
29 #include <canobserver.h>
30
31 #include <ambpluginimpl.h>
32 #include "websockets.h"
33
34 /*!
35  *  \defgroup cangenplugin cangenplugin shared library.
36  *
37  *  \brief CANGenPlugin generates CAN frames for CANSimPlugin based on WebSocket Simulator API requests.
38  *
39  *  CANGenPlugin is a source plug-in for Automotive message broker(AMB). \n
40  *  For the AMB library API please visit <a href="https://github.com/otcshare/automotive-message-broker">Automotive message broker web page</a>.\n
41  *
42  *  To load this plugin at AMB starup, insert following rows into AMB configuration file:
43  *  \code
44  *      {
45  *          "name" : "CANGenPlugin",
46  *          "path":"/usr/lib/automotive-message-broker/cangenplugin.so"
47  *      }
48  *  \endcode
49  *
50  *  It supports following Simulator API commands:
51  *      \li Simulator.get() - Get property request - JSON in the form:
52  *              \code {"type":"method","name":"get","transactionid":"862bb93d-a302-9a58-baa9-d90265ac843c","data":[{"property":"VehicleSpeed","zone":"0"}]} \endcode
53  *          CANGenPlugin replies to this command with actual value, timestamp and sequence number of the requested property with the JSON in the form:\n
54  *              \code {"type":"methodReply","name":"get","data":{"property":"VehicleSpeed","zone":"0","value":"35","timestamp":"1388656508.34255","sequence": "2"},"transactionid":"862bb93d-a302-9a58-baa9-d90265ac843c"} \endcode
55  *      \li Simulator.set() - Set property request(simulation of the property new value) - JSON in the form:\n
56  *               \code {"type":"method","name":"set","transactionid":"d5935c94-7b05-fd67-56bc-31c320185035","data":[{"interface":"vcan0","property":"VehicleSpeed","value":"33","zone":"0"}]} \endcode
57  *          Based on property name and zone CANGenPlugin finds corresponding CAN Id of the requested property, builds CAN frame and sends it via specified CAN interface in the host OS.\n
58  *          I replies back to the Simulator with the operation error code on failure or without error code on success:\n
59  *              \code {"type":"methodReply","name":"set","data":[{"property":"VehicleSpeed"}],"transactionid":"d5935c94-7b05-fd67-56bc-31c320185035","error":"method call failed"} \endcode
60  *              \code {"type":"methodReply","name":"set","data":[{"property":"VehicleSpeed"}],"transactionid":"d5935c94-7b05-fd67-56bc-31c320185035"}\endcode
61  *
62  *  @{
63  */
64
65 /*!
66  * \brief CAN frames generator plug-in for the AMB CAN Simulator.
67  *
68  *  On startup it subscribe and reads 'MappingTable' property from CANSimPlugin, parses it and build
69  *  own mapping table(AMB property to CAN Id map) of all properties from CANSimPlugin that can be simulated.\n
70  *  In parallel to building mapping table of the AMB properties and their corresponding CAN Ids it starts listening for javascrip Simulator API commands on WebSocket port \p \b 23001. \n
71  *
72  * \see \ref libcanbus
73  * \class CANGenPlugin
74  */
75
76 static const char* CANSimPluginUUID = "3f43e231-11ec-4782-9b5a-3dbcc5221eeb";
77
78 class CANGenPlugin: public AmbPluginImpl, public CANObserver, public WebSocketsObserver {
79
80 public:
81
82         /*!
83          * \param re AbstractRoutingEngine
84          * \param config Map of the configuration string values loaded on startup from AMB configuration file
85          * \param parent AmbPlugin instance
86          */
87         CANGenPlugin(AbstractRoutingEngine* re, const std::map<std::string, std::string>& config, AbstractSource &parent);
88         virtual ~CANGenPlugin(); // has to be virtual because of unit tests
89
90         // from AbstractSink
91 public:
92
93         /*! uuid() is a unique identifier of the plugin
94          * @return a guid-style unique identifier
95          */
96         const std::string uuid() const { return "becbbef9-6cc8-4b9e-8cd7-2fbe37b9b52a"; }
97
98         /*! propertyChanged is called when a subscribed to property changes.
99           * @see AbstractRoutingEngine::subscribeToPropertyChanges()
100           * \param value value of the property that changed. this is a temporary pointer that will be destroyed.
101           * Do not destroy it.  If you need to store the value use value.anyValue(), value.value<T>() or
102           * value->copy() to copy.
103           */
104         void propertyChanged(AbstractPropertyType* value);
105
106         AsyncPropertyReply* setProperty(const AsyncSetPropertyRequest &request);
107
108         // from CANObserver
109 public:
110         /*!
111          * Called when error occurred on the bus.
112          * \fn errorOccured
113          * \param error \link CANObserver#CANError Bus error code \endlink
114          */
115         virtual void errorOccured(CANObserver::CANError error);/* socket error */
116         /*!
117          * Called when standard frame was is received from the bus.
118          * \fn standardFrameReceived
119          * \param frame Received frame
120          */
121         virtual void standardFrameReceived(const can_frame& frame);/* SFF was present */
122         /*!
123          * Called when extended frame was is received from the bus.
124          * \fn extendedFrameReceived
125          * \param frame Received frame
126          */
127         virtual void extendedFrameReceived(const can_frame& frame);/* EFF was present */
128         /*!
129          * Called when error frame was received from the bus.
130          * \fn errorFrameReceived
131          * \param frame Error frame
132          */
133         virtual void errorFrameReceived(const can_frame& frame);/* error frame */
134         /*!
135          * Called when remote transmission frame was received from the bus.
136          * \fn remoteTransmissionRequest
137          * \param frame RTR frame
138          */
139         virtual void remoteTransmissionRequest(const can_frame& frame);/* remote transmission request (SFF/EFF is still present)*/
140         /**
141         * Called when timeout was detected for a cyclic message.
142         * @fn timeoutDetected
143         * @param frame
144         */
145         virtual void timeoutDetected(const can_frame& frame);
146
147         /*!
148          * Second phase of the plugin initialization.
149          * \fn init
150          */
151         virtual void init();
152
153         // from WebSocketsObserver
154
155         /*!
156          * Called when data received from libwebsockets
157          * \fn dataReceived
158          * \param socket libwebsocket* to be used to send any reply.
159          * \param data Received data pointer.
160          * \param len Length of the data.
161          * \return None
162          */
163         void dataReceived(libwebsocket* socket, const char* data, size_t len);
164
165 //
166 // Internal methods:
167 //
168 private:
169
170         /*!
171          * \brief Prints received CAN frame
172          * \param frame Received CAN frame.
173          * \internal
174          * \private
175          */
176         void printFrame(const can_frame& frame) const;
177
178         /*!
179          * Parses 'MappingTable' property from CANSimPlugin.
180          * Result is stored in internal MappingTable class(AMB property and Zone to CAN Id map) which contains all properties that can be simulated.
181          * \param json Content of the 'MappingTable' property in JSON format.
182          */
183         void parseMappingTable(const std::string& json);
184
185         /*!
186          * \brief Simulator.get request handler function.
187          * Builds and sends reply with the property value, timestamp and sequence number in JSON format.
188          * \param socket libwebsocket handle to be used to send reply.
189          * \param property Name of the property.
190          * \param zone Property's zone.
191          * \param uuid Request's transaction id.
192          * \private
193          */
194         void getValue(libwebsocket* socket, const std::string& property, int zone, const std::string& uuid);
195
196         /*!
197          * \brief Simulator.set request handler function.
198          * Formats property's value as a AMB's AbstractPropertyValue and passes it to sendValue. Reply to the Simulator with reply string in JSON format.
199          * \param socket libwebsocket handle to be used to send reply.
200          * \param property Name of the property.
201          * \param value Property's new value to be simulated.
202          * \param zone Property's zone.
203          * \param interface CAN interface to be used to send CAN frame.
204          * \param transactionId Request's transaction id.
205          * \private
206          */
207         void setValue(libwebsocket* socket, const std::string& property, const std::string& value, int zone, const std::string& interface, const std::string& transactionId);
208
209         /*!
210          * \brief Build and sends CAN frame to CANSimPlugin.
211          * Finds CAN Id using mappingTable for requested property name and zone, builds CAN frame with the property's new value and tries to send it via requested CAN interface.
212          * \param interface CAN interface to be used to send CAN frame.
213          * \param value AMB's AbstractPropertyValue which encapsulates property name, zone and value.
214          * \return true if CAN frame was successfully sent, otherwise false.
215          * \private
216          */
217         bool sendValue(const std::string& interface, AbstractPropertyType* value);
218
219         /*!
220          * Internal helper class
221          * AMB property and property's zone to CAN Id map
222          * \class MappingTable
223          * \private
224          * \internal
225          *
226          */
227         class MappingTable{
228         public:
229                 MappingTable()
230                 {
231                 }
232
233                 MappingTable(const MappingTable& other) = delete;
234                 MappingTable& operator=(const MappingTable& other) = delete;
235                 MappingTable(MappingTable&& other) = default;
236                 MappingTable& operator=(MappingTable&& other) = default;
237
238                 void addProperty(const std::string& source, json_object* signal)
239                 {
240                         json_object* canIdObj = json_object_object_get(signal, "can_id");
241                         json_object* nameObj = json_object_object_get(signal, "name");
242                         if(!canIdObj || !nameObj) // mandatory
243                                 return;
244                         Zone::Type zone(Zone::None);
245                         json_object* zoneObj = json_object_object_get(signal, "zone");
246                         if(zoneObj)
247                                 zone = json_object_get_int(zoneObj);
248
249                         auto& zp = mapping[source];
250                         auto& prop = zp[Zone::Type(zone)];
251                         std::string name(json_object_get_string(nameObj));
252                         int can_id = json_object_get_int(canIdObj);
253                         prop[name] = can_id; // update an existing value
254                 }
255
256                 int getCanId(const std::string& source, const Zone::Type& zone, const VehicleProperty::Property& name) const
257                 {
258                         //return mapping[source][zone][name]; // caution! this will insert if not found. I don't want it.
259                         auto sourceIt = mapping.find(source);
260                         if(sourceIt == mapping.end())
261                                 return 0;
262                         auto zoneIt = sourceIt->second.find(zone);
263                         if(zoneIt == sourceIt->second.end())
264                                 return 0;
265                         auto propIt = zoneIt->second.find(name);
266                         if(propIt == zoneIt->second.end())
267                                 return 0;
268                         else
269                                 return propIt->second;
270                 }
271
272                 void clear()
273                 {
274                         mapping.clear();
275                 }
276
277         private:
278                 typedef std::map< Zone::Type, std::map<VehicleProperty::Property, canid_t> > ZonedProperty;
279                 std::map<std::string, ZonedProperty> mapping;
280         };
281
282 //
283 // data:
284 //
285
286         /*!
287          * AMB property and property's zone to CAN Id map
288          * \private
289          */
290         MappingTable mappingTable;
291
292         /*!
293          * Opened CAN interfaces used to send CAN frames
294          * \private
295          */
296         std::map<std::string, std::shared_ptr<CANBus> > interfaces;
297
298         /*!
299          * Encapsulated libwebsocket library
300          * \private
301          */
302         std::unique_ptr<WebSockets> ws;
303
304         /*!
305          * Mutex to protect mappingTable container during property 'MappingTable' parsing on change notification
306          * \private
307          */
308         interprocess_recursive_mutex mutex;
309 };
310
311 class SimCommand: public StringPropertyType
312 {
313 public:
314         SimCommand(): StringPropertyType("SimCommand") { }
315         SimCommand(std::string val) : StringPropertyType("SimCommand",val) { }
316 };
317
318 #endif // _CANGENPLUGINIMPL_H_
319
320 /** @} */