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 #ifndef _CANGENPLUGINIMPL_H_
20 #define _CANGENPLUGINIMPL_H_
25 #include <libwebsockets.h>
29 #include <canobserver.h>
31 #include <ambpluginimpl.h>
32 #include "websockets.h"
35 * \defgroup cangenplugin cangenplugin shared library.
37 * \brief CANGenPlugin generates CAN frames for CANSimPlugin based on WebSocket Simulator API requests.
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
42 * To load this plugin at AMB starup, insert following rows into AMB configuration file:
45 * "name" : "CANGenPlugin",
46 * "path":"/usr/lib/automotive-message-broker/cangenplugin.so"
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
66 * \brief CAN frames generator plug-in for the AMB CAN Simulator.
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
76 static const char* CANSimPluginUUID = "3f43e231-11ec-4782-9b5a-3dbcc5221eeb";
78 class CANGenPlugin: public AmbPluginImpl, public CANObserver, public WebSocketsObserver {
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
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
93 /*! uuid() is a unique identifier of the plugin
94 * @return a guid-style unique identifier
96 const std::string uuid() const { return "becbbef9-6cc8-4b9e-8cd7-2fbe37b9b52a"; }
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.
104 void propertyChanged(AbstractPropertyType* value);
106 AsyncPropertyReply* setProperty(const AsyncSetPropertyRequest &request);
111 * Called when error occurred on the bus.
113 * \param error \link CANObserver#CANError Bus error code \endlink
115 virtual void errorOccured(CANObserver::CANError error);/* socket error */
117 * Called when standard frame was is received from the bus.
118 * \fn standardFrameReceived
119 * \param frame Received frame
121 virtual void standardFrameReceived(const can_frame& frame);/* SFF was present */
123 * Called when extended frame was is received from the bus.
124 * \fn extendedFrameReceived
125 * \param frame Received frame
127 virtual void extendedFrameReceived(const can_frame& frame);/* EFF was present */
129 * Called when error frame was received from the bus.
130 * \fn errorFrameReceived
131 * \param frame Error frame
133 virtual void errorFrameReceived(const can_frame& frame);/* error frame */
135 * Called when remote transmission frame was received from the bus.
136 * \fn remoteTransmissionRequest
137 * \param frame RTR frame
139 virtual void remoteTransmissionRequest(const can_frame& frame);/* remote transmission request (SFF/EFF is still present)*/
141 * Called when timeout was detected for a cyclic message.
142 * @fn timeoutDetected
145 virtual void timeoutDetected(const can_frame& frame);
148 * Second phase of the plugin initialization.
153 // from WebSocketsObserver
156 * Called when data received from libwebsockets
158 * \param socket libwebsocket* to be used to send any reply.
159 * \param data Received data pointer.
160 * \param len Length of the data.
163 void dataReceived(libwebsocket* socket, const char* data, size_t len);
171 * \brief Prints received CAN frame
172 * \param frame Received CAN frame.
176 void printFrame(const can_frame& frame) const;
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.
183 void parseMappingTable(const std::string& json);
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.
194 void getValue(libwebsocket* socket, const std::string& property, int zone, const std::string& uuid);
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.
207 void setValue(libwebsocket* socket, const std::string& property, const std::string& value, int zone, const std::string& interface, const std::string& transactionId);
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.
217 bool sendValue(const std::string& interface, AbstractPropertyType* value);
220 * Internal helper class
221 * AMB property and property's zone to CAN Id map
222 * \class MappingTable
233 MappingTable(const MappingTable& other) = delete;
234 MappingTable& operator=(const MappingTable& other) = delete;
235 MappingTable(MappingTable&& other) = default;
236 MappingTable& operator=(MappingTable&& other) = default;
238 void addProperty(const std::string& source, json_object* signal)
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
244 Zone::Type zone(Zone::None);
245 json_object* zoneObj = json_object_object_get(signal, "zone");
247 zone = json_object_get_int(zoneObj);
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
256 int getCanId(const std::string& source, const Zone::Type& zone, const VehicleProperty::Property& name) const
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())
262 auto zoneIt = sourceIt->second.find(zone);
263 if(zoneIt == sourceIt->second.end())
265 auto propIt = zoneIt->second.find(name);
266 if(propIt == zoneIt->second.end())
269 return propIt->second;
278 typedef std::map< Zone::Type, std::map<VehicleProperty::Property, canid_t> > ZonedProperty;
279 std::map<std::string, ZonedProperty> mapping;
287 * AMB property and property's zone to CAN Id map
290 MappingTable mappingTable;
293 * Opened CAN interfaces used to send CAN frames
296 std::map<std::string, std::shared_ptr<CANBus> > interfaces;
299 * Encapsulated libwebsocket library
302 std::unique_ptr<WebSockets> ws;
305 * Mutex to protect mappingTable container during property 'MappingTable' parsing on change notification
308 interprocess_recursive_mutex mutex;
311 class SimCommand: public StringPropertyType
314 SimCommand(): StringPropertyType("SimCommand") { }
315 SimCommand(std::string val) : StringPropertyType("SimCommand",val) { }
318 #endif // _CANGENPLUGINIMPL_H_