1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2007-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    MSDevice.h
11 /// @author  Michael Behrisch
12 /// @author  Daniel Krajzewicz
13 /// @author  Jakob Erdmann
14 /// @date    Tue, 04 Dec 2007
15 /// @version $Id$
16 ///
17 // Abstract in-vehicle device
18 /****************************************************************************/
19 #ifndef MSDevice_h
20 #define MSDevice_h
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <string>
29 #include <vector>
30 #include <map>
31 #include <set>
32 #include <random>
33 #include <microsim/MSMoveReminder.h>
34 #include <microsim/MSVehicleType.h>
35 #include <microsim/MSVehicleControl.h>
36 #include <utils/common/Named.h>
37 #include <utils/common/StringUtils.h>
38 #include <utils/common/UtilExceptions.h>
39 #include <utils/options/OptionsCont.h>
40 
41 
42 // ===========================================================================
43 // class declarations
44 // ===========================================================================
45 class OutputDevice;
46 class SUMOVehicle;
47 class MSTransportable;
48 class SUMOSAXAttributes;
49 class MSVehicleDevice;
50 class MSTransportableDevice;
51 
52 
53 // ===========================================================================
54 // class definitions
55 // ===========================================================================
56 /**
57  * @class MSDevice
58  * @brief Abstract in-vehicle / in-person device
59  *
60  * The MSDevice-interface brings the following interfaces to a vehicle /person that
61  *  may be overwritten by real devices:
62  * @arg Building and retrieval of a device id
63  */
64 class MSDevice : public Named {
65 public:
66     /** @brief Inserts options for building devices
67      * @param[filled] oc The options container to add the options to
68      */
69     static void insertOptions(OptionsCont& oc);
70 
71     /** @brief check device-specific options
72      * @param[filled] oc The options container with the user-defined options
73      */
74     static bool checkOptions(OptionsCont& oc);
75 
76 
77     /** @brief Build devices for the given vehicle, if needed
78     *
79     * @param[in] v The vehicle for which a device may be built
80     * @param[filled] into The vector to store the built device in
81     */
82     static void buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into);
83 
84     /** @brief Build devices for the given person, if needed
85     *
86     * @param[in] p The person for which a device may be built
87     * @param[filled] into The vector to store the built device in
88     */
89     static void buildTransportableDevices(MSTransportable& p, std::vector<MSTransportableDevice*>& into);
90 
getEquipmentRNG()91     static std::mt19937* getEquipmentRNG() {
92         return &myEquipmentRNG;
93     }
94 
95     /// @brief return the name for this type of device
96     virtual const std::string deviceName() const = 0;
97 
98     /// @brief perform cleanup for all devices
99     static void cleanupAll();
100 
101 public:
102     /** @brief Constructor
103      *
104      * @param[in] id The ID of the device
105      */
MSDevice(const std::string & id)106     MSDevice(const std::string& id) : Named(id) {
107     }
108 
109 
110     /// @brief Destructor
~MSDevice()111     virtual ~MSDevice() { }
112 
113 
114     /** @brief Called on writing tripinfo output
115      *
116      * The device may write some statistics into the tripinfo output. It
117      *  is assumed that the written information is a valid xml-snipplet, which
118      *  will be embedded within the vehicle's information.
119      *
120      * The device should use the openTag / closeTag methods of the OutputDevice
121      *  for correct indentation.
122      *
123      * @exception IOError not yet implemented
124      */
generateOutput()125     virtual void generateOutput() const {
126     }
127 
128     /** @brief Saves the state of the device
129      *
130      * The default implementation writes a warning and does nothing.
131      * @param[in] out The OutputDevice to write the information into
132      */
133     virtual void saveState(OutputDevice& out) const;
134 
135 
136     /** @brief Loads the state of the device from the given description
137      *
138      * The default implementation does nothing.
139      * @param[in] attrs XML attributes describing the current state
140      */
141     virtual void loadState(const SUMOSAXAttributes& attrs);
142 
143     /// @brief try to retrieve the given parameter from this device. Throw exception for unsupported key
getParameter(const std::string & key)144     virtual std::string getParameter(const std::string& key) const {
145         throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
146     }
147 
148     /// @brief try to set the given parameter for this device. Throw exception for unsupported key
setParameter(const std::string & key,const std::string & value)149     virtual void setParameter(const std::string& key, const std::string& value) {
150         UNUSED_PARAMETER(value);
151         throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
152     }
153 
154 protected:
155     /// @name Helper methods for device assignment
156     /// @{
157 
158     /** @brief Adds common command options that allow to assign devices to vehicles
159      *
160      * @param[in] deviceName The name of the device type
161      * @param[in] optionsTopic The options topic into which the options shall be added
162      * @param[filled] oc The options container to add the options to
163      */
164     static void insertDefaultAssignmentOptions(const std::string& deviceName, const std::string& optionsTopic, OptionsCont& oc, const bool isPerson = false);
165 
166 
167     /** @brief Determines whether a vehicle should get a certain device
168      *
169      * @param[in] oc The options container to get the information about assignment from
170      * @param[in] deviceName The name of the device type
171      * @param[in] v The vehicle to determine whether it shall be equipped or not
172      */
173     template<class DEVICEHOLDER>
174     static bool equippedByDefaultAssignmentOptions(const OptionsCont& oc, const std::string& deviceName, DEVICEHOLDER& v, bool outputOptionSet, const bool isPerson = false);
175     /// @}
176 
177 
178     /// @name Helper methods for parsing parameters
179     /// @{
180     static std::string getStringParam(const SUMOVehicle& v, const OptionsCont& oc, std::string paramName, std::string deflt, bool required);
181     static double getFloatParam(const SUMOVehicle& v, const OptionsCont& oc, std::string paramName, double deflt, bool required);
182     static bool getBoolParam(const SUMOVehicle& v, const OptionsCont& oc, std::string paramName, bool deflt, bool required);
183     /// @}
184 
185 private:
186     /// @brief vehicles which explicitly carry a device, sorted by device, first
187     static std::map<std::string, std::set<std::string> > myExplicitIDs;
188 
189     /// @brief A random number generator used to choose from vtype/route distributions and computing the speed factors
190     static std::mt19937 myEquipmentRNG;
191 
192 
193 private:
194     /// @brief Invalidated copy constructor.
195     MSDevice(const MSDevice&);
196 
197     /// @brief Invalidated assignment operator.
198     MSDevice& operator=(const MSDevice&);
199 
200 };
201 
202 
203 template<class DEVICEHOLDER> bool
equippedByDefaultAssignmentOptions(const OptionsCont & oc,const std::string & deviceName,DEVICEHOLDER & v,bool outputOptionSet,const bool isPerson)204 MSDevice::equippedByDefaultAssignmentOptions(const OptionsCont& oc, const std::string& deviceName, DEVICEHOLDER& v, bool outputOptionSet, const bool isPerson) {
205     const std::string prefix = (isPerson ? "person-device." : "device.") + deviceName;
206     // assignment by number
207     bool haveByNumber = false;
208     bool numberGiven = false;
209     if (oc.exists(prefix + ".deterministic") && oc.getBool(prefix + ".deterministic")) {
210         numberGiven = true;
211         haveByNumber = MSNet::getInstance()->getVehicleControl().getQuota(oc.getFloat(prefix + ".probability")) == 1;
212     } else {
213         if (oc.exists(prefix + ".probability") && oc.getFloat(prefix + ".probability") >= 0) {
214             numberGiven = true;
215             haveByNumber = RandHelper::rand(&myEquipmentRNG) <= oc.getFloat(prefix + ".probability");
216         }
217     }
218     // assignment by name
219     bool haveByName = false;
220     bool nameGiven = false;
221     if (oc.exists(prefix + ".explicit") && oc.isSet(prefix + ".explicit")) {
222         nameGiven = true;
223         if (myExplicitIDs.find(deviceName) == myExplicitIDs.end()) {
224             myExplicitIDs[deviceName] = std::set<std::string>();
225             const std::vector<std::string> idList = OptionsCont::getOptions().getStringVector(prefix + ".explicit");
226             myExplicitIDs[deviceName].insert(idList.begin(), idList.end());
227         }
228         haveByName = myExplicitIDs[deviceName].count(v.getID()) > 0;
229     }
230     // assignment by abstract parameters
231     bool haveByParameter = false;
232     bool parameterGiven = false;
233     const std::string key = "has." + deviceName + ".device";
234     if (v.getParameter().knowsParameter(key)) {
235         parameterGiven = true;
236         haveByParameter = StringUtils::toBool(v.getParameter().getParameter(key, "false"));
237     } else if (v.getVehicleType().getParameter().knowsParameter(key)) {
238         parameterGiven = true;
239         haveByParameter = StringUtils::toBool(v.getVehicleType().getParameter().getParameter(key, "false"));
240     }
241     if (haveByName) {
242         return true;
243     } else if (parameterGiven) {
244         return haveByParameter;
245     } else if (numberGiven) {
246         return haveByNumber;
247     } else {
248         return !nameGiven && outputOptionSet;
249     }
250 }
251 
252 
253 #endif
254 
255 /****************************************************************************/
256