LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Bluelight.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.7 % 168 149
Test Date: 2025-11-13 15:38:19 Functions: 83.3 % 12 10

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2013-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSDevice_Bluelight.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Michael Behrisch
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Laura Bieker
      19              : /// @date    01.06.2017
      20              : ///
      21              : // A device for emergency vehicle. The behaviour of other traffic participants will be triggered with this device.
      22              : // For example building a rescue lane.
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <utils/common/StringUtils.h>
      27              : #include <utils/common/StringTokenizer.h>
      28              : #include <utils/options/OptionsCont.h>
      29              : #include <utils/iodevices/OutputDevice.h>
      30              : #include <utils/vehicle/SUMOVehicle.h>
      31              : #include <microsim/MSNet.h>
      32              : #include <microsim/MSLane.h>
      33              : #include <microsim/MSEdge.h>
      34              : #include <microsim/MSLink.h>
      35              : #include <microsim/MSVehicle.h>
      36              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      37              : #include <microsim/MSVehicleControl.h>
      38              : #include <microsim/MSVehicleType.h>
      39              : #include "MSDevice_Tripinfo.h"
      40              : #include "MSDevice_Bluelight.h"
      41              : 
      42              : //#define DEBUG_BLUELIGHT
      43              : //#define DEBUG_BLUELIGHT_RESCUELANE
      44              : 
      45              : #define INFLUENCED_BY "rescueLane"
      46              : 
      47              : // ===========================================================================
      48              : // method definitions
      49              : // ===========================================================================
      50              : // ---------------------------------------------------------------------------
      51              : // static initialisation methods
      52              : // ---------------------------------------------------------------------------
      53              : void
      54        39784 : MSDevice_Bluelight::insertOptions(OptionsCont& oc) {
      55        39784 :     oc.addOptionSubTopic("Bluelight Device");
      56        79568 :     insertDefaultAssignmentOptions("bluelight", "Bluelight Device", oc);
      57              : 
      58        39784 :     oc.doRegister("device.bluelight.reactiondist", new Option_Float(25.0));
      59        79568 :     oc.addDescription("device.bluelight.reactiondist", "Bluelight Device", TL("Set the distance at which other drivers react to the blue light and siren sound"));
      60        39784 :     oc.doRegister("device.bluelight.mingapfactor", new Option_Float(1.));
      61        79568 :     oc.addDescription("device.bluelight.mingapfactor", "Bluelight Device", TL("Reduce the minGap for reacting vehicles by the given factor"));
      62        39784 : }
      63              : 
      64              : 
      65              : void
      66      5371069 : MSDevice_Bluelight::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
      67      5371069 :     OptionsCont& oc = OptionsCont::getOptions();
      68     10742138 :     if (equippedByDefaultAssignmentOptions(oc, "bluelight", v, false)) {
      69          208 :         if (MSGlobals::gUseMesoSim) {
      70            0 :             WRITE_WARNINGF(TL("bluelight device is not compatible with mesosim (ignored for vehicle '%')"), v.getID());
      71              :         } else {
      72          416 :             MSDevice_Bluelight* device = new MSDevice_Bluelight(v, "bluelight_" + v.getID(),
      73              :                     v.getFloatParam("device.bluelight.reactiondist"),
      74          624 :                     v.getFloatParam("device.bluelight.mingapfactor"));
      75          208 :             into.push_back(device);
      76              :         }
      77              :     }
      78      5371069 : }
      79              : 
      80              : 
      81              : // ---------------------------------------------------------------------------
      82              : // MSDevice_Bluelight-methods
      83              : // ---------------------------------------------------------------------------
      84          208 : MSDevice_Bluelight::MSDevice_Bluelight(SUMOVehicle& holder, const std::string& id,
      85          208 :                                        const double reactionDist, const double minGapFactor) :
      86              :     MSVehicleDevice(holder, id),
      87          208 :     myReactionDist(reactionDist),
      88          208 :     myMinGapFactor(minGapFactor) {
      89              : #ifdef DEBUG_BLUELIGHT
      90              :     std::cout << SIMTIME << " initialized device '" << id << "' with myReactionDist=" << myReactionDist << "\n";
      91              : #endif
      92              :     // set only once to permit TraCI override
      93          208 :     MSVehicle& veh = dynamic_cast<MSVehicle&>(holder);
      94          208 :     veh.getInfluencer().setSpeedMode(7);
      95          208 : }
      96              : 
      97              : 
      98          416 : MSDevice_Bluelight::~MSDevice_Bluelight() {
      99          416 : }
     100              : 
     101              : 
     102              : bool
     103        65189 : MSDevice_Bluelight::notifyMove(SUMOTrafficObject& veh, double /* oldPos */,
     104              :                                double /* newPos */, double newSpeed) {
     105              : #ifdef DEBUG_BLUELIGHT
     106              :     std::cout << SIMTIME  << " device '" << getID() << "' notifyMove: newSpeed=" << newSpeed << "\n";
     107              : #else
     108              :     UNUSED_PARAMETER(newSpeed);
     109              : #endif
     110              :     //violate red lights  this only need to be done once so shift it todo
     111        65189 :     MSVehicle& ego = dynamic_cast<MSVehicle&>(veh);
     112        65189 :     MSVehicle::Influencer& redLight = ego.getInfluencer();
     113        65189 :     const double vMax = ego.getLane()->getVehicleMaxSpeed(&ego);
     114        65189 :     if (ego.getSpeed() < 0.5 * vMax) {
     115              :         // advance as far as possible (assume vehicles will keep moving out of the way)
     116        63196 :         ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM), "-1");
     117        63196 :         ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD), "0");
     118        63196 :         ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME), "0");
     119              :         try {
     120        63196 :             ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_MINGAP_LAT), "0");
     121          426 :         } catch (InvalidArgument&) {
     122              :             // not supported by the current laneChangeModel
     123          426 :         }
     124              :     } else {
     125              :         // restore defaults
     126       100773 :         ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM),
     127        33591 :                                               ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_STRATEGIC_PARAM, "1"));
     128       100773 :         ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD),
     129        33591 :                                               ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD, "5"));
     130       100773 :         ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME),
     131        33591 :                                               ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME, "20"));
     132              :         try {
     133       100773 :             ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_MINGAP_LAT),
     134        64662 :                                                   toString(ego.getVehicleType().getMinGapLat()));
     135         2520 :         } catch (InvalidArgument&) {
     136              :             // not supported by the current laneChangeModel
     137         2520 :         }
     138              :     }
     139              :     // build a rescue lane for all vehicles on the route of the emergency vehicle within the range of the siren
     140        65189 :     MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     141              :     // use edges on the way of the emergency vehicle
     142              :     std::vector<const MSEdge*> upcomingEdges;
     143              :     std::set<MSVehicle*, ComparatorIdLess> upcomingVehicles;
     144              :     std::set<std::string> lastStepInfluencedVehicles = myInfluencedVehicles;
     145              :     std::vector<MSLink*> upcomingLinks;
     146        65189 :     double affectedJunctionDist = ego.getPositionOnLane() + myReactionDist;
     147       188949 :     for (const MSLane* const l : ego.getUpcomingLanesUntil(myReactionDist)) {
     148       123760 :         upcomingEdges.push_back(&l->getEdge());
     149              : 
     150       123760 :         affectedJunctionDist -= l->getLength();
     151       123760 :         if (affectedJunctionDist > 0 && l->isInternal()) {
     152        29453 :             upcomingLinks.push_back(l->getIncomingLanes()[0].viaLink);
     153              :         }
     154        65189 :     }
     155              : 
     156       188949 :     for (const MSEdge* const e : upcomingEdges) {
     157              :         //inform all vehicles on upcomingEdges
     158       668546 :         for (const SUMOVehicle* v : e->getVehicles()) {
     159       544786 :             upcomingVehicles.insert(dynamic_cast<MSVehicle*>(const_cast<SUMOVehicle*>(v)));
     160              :             if (lastStepInfluencedVehicles.count(v->getID()) > 0) {
     161              :                 lastStepInfluencedVehicles.erase(v->getID());
     162              :             }
     163       123760 :         }
     164              :     }
     165              :     // reset all vehicles that were in myInfluencedVehicles in the previous step but not in the current step todo refactor
     166        66626 :     for (std::string vehID : lastStepInfluencedVehicles) {
     167              :         myInfluencedVehicles.erase(vehID);
     168              :         Parameterised::Map::iterator it = myInfluencedTypes.find(vehID);
     169         1437 :         MSVehicle* veh2 = dynamic_cast<MSVehicle*>(vc.getVehicle(vehID));
     170         1384 :         if (veh2 != nullptr && it != myInfluencedTypes.end()) {
     171              :             // The vehicle gets back its old VehicleType after the emergency vehicle have passed them
     172         1384 :             resetVehicle(veh2, it->second);
     173              :         }
     174              :     }
     175              : 
     176       609975 :     for (MSVehicle* veh2 : upcomingVehicles) {
     177              :         assert(veh2 != nullptr);
     178       544786 :         if (veh2->getLane() == nullptr) {
     179            0 :             continue;
     180              :         }
     181       544786 :         if (std::find(upcomingEdges.begin(), upcomingEdges.end(), &veh2->getLane()->getEdge()) != upcomingEdges.end()) {
     182       544782 :             if (veh2->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
     183              :                 // emergency vehicles should not react
     184       277082 :                 continue;
     185              :             }
     186       267700 :             const int numLanes = (int)veh2->getLane()->getEdge().getNumLanes();
     187              :             // make sure that vehicles are still building the rescue lane as they might have moved to a new edge or changed lanes
     188              :             if (myInfluencedVehicles.count(veh2->getID()) > 0) {
     189              :                 // Vehicle gets a new Vehicletype to change the alignment and the lanechange options
     190       124004 :                 MSVehicleType& t = veh2->getSingularType();
     191              :                 // Setting the lateral alignment to build a rescue lane
     192       124004 :                 LatAlignmentDefinition align = LatAlignmentDefinition::RIGHT;
     193       124004 :                 if (veh2->getLane()->getIndex() == numLanes - 1) {
     194        52484 :                     align = LatAlignmentDefinition::LEFT;
     195              :                 }
     196       124004 :                 t.setPreferredLateralAlignment(align);
     197              : #ifdef DEBUG_BLUELIGHT_RESCUELANE
     198              :                 std::cout << "Refresh alignment for vehicle: " << veh2->getID()
     199              :                           << " laneIndex=" << veh2->getLane()->getIndex() << " numLanes=" << numLanes
     200              :                           << " alignment=" << toString(align) << "\n";
     201              : #endif
     202              :             }
     203              : 
     204       267700 :             double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
     205              :             //emergency vehicle has to slow down when entering the rescue lane
     206       297678 :             if (distanceDelta <= 10 && veh.getID() != veh2->getID() && myInfluencedVehicles.count(veh2->getID()) > 0 && veh2->getSpeed() < 1) {
     207              :                 // set ev speed to 20 km/h 0 5.56 m/s
     208        28590 :                 const double redSpeed = ego.getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, 5.56);
     209              :                 std::vector<std::pair<SUMOTime, double> > speedTimeLine;
     210        28590 :                 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh.getSpeed()));
     211        28590 :                 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(2), redSpeed));
     212        28590 :                 redLight.setSpeedTimeLine(speedTimeLine);
     213        28590 :             }
     214              : 
     215              :             // the perception of the sound of the siren should be around 25 meters
     216              :             // todo only vehicles in front of the emergency vehicle should react
     217       267700 :             if (distanceDelta <= myReactionDist && veh.getID() != veh2->getID() && myInfluencedVehicles.count(veh2->getID()) == 0) {
     218              :                 // only a percentage of vehicles should react to the emergency vehicle to make the behaviour more realistic
     219        18088 :                 double reaction = RandHelper::rand();
     220        18088 :                 MSVehicle::Influencer& lanechange = veh2->getInfluencer();
     221              : 
     222              :                 //other vehicle should not use the rescue lane so they should not make any lane changes
     223        18088 :                 lanechange.setLaneChangeMode(1605);//todo change lane back
     224              :                 // the vehicles should react according to the distance to the emergency vehicle taken from real world data
     225              :                 double reactionProb = (
     226        18088 :                                           distanceDelta < myHolder.getFloatParam("device.bluelight.near-dist", false, 12.5)
     227        36176 :                                           ? myHolder.getFloatParam("device.bluelight.reaction-prob-near", false, 0.577)
     228        35473 :                                           : myHolder.getFloatParam("device.bluelight.reaction-prob-far", false, 0.189));
     229              :                 // todo works only for one second steps
     230              :                 //std::cout << SIMTIME << " veh2=" << veh2->getID() << " distanceDelta=" << distanceDelta << " reaction=" << reaction << " reactionProb=" << reactionProb << "\n";
     231        18088 :                 if (veh2->isActionStep(SIMSTEP) && reaction < reactionProb * veh2->getActionStepLengthSecs()) {
     232              :                     myInfluencedVehicles.insert(veh2->getID());
     233         2874 :                     myInfluencedTypes.insert(std::make_pair(veh2->getID(), veh2->getVehicleType().getID()));
     234         1437 :                     if (myMinGapFactor != 1.) {
     235              :                         // TODO this is a permanent change to the vtype!
     236           12 :                         MSNet::getInstance()->getVehicleControl().getVType(veh2->getVehicleType().getID())->getCarFollowModel().setCollisionMinGapFactor(myMinGapFactor);
     237              :                     }
     238              : 
     239              :                     // Vehicle gets a new Vehicletype to change the alignment and the lanechange options
     240         1437 :                     MSVehicleType& t = veh2->getSingularType();
     241              :                     // Setting the lateral alignment to build a rescue lane
     242         1437 :                     LatAlignmentDefinition align = LatAlignmentDefinition::RIGHT;
     243         1437 :                     if (veh2->getLane()->getIndex() == numLanes - 1) {
     244          676 :                         align = LatAlignmentDefinition::LEFT;
     245              :                     }
     246         1437 :                     t.setPreferredLateralAlignment(align);
     247         1437 :                     t.setMinGap(t.getMinGap() * myMinGapFactor);
     248         1437 :                     const_cast<SUMOVTypeParameter&>(t.getParameter()).jmParameter[SUMO_ATTR_JM_STOPLINE_GAP] = toString(myMinGapFactor);
     249              :                     // disable strategic lane-changing
     250              : #ifdef DEBUG_BLUELIGHT_RESCUELANE
     251              :                     std::cout << SIMTIME << " device=" << getID() << " formingRescueLane=" << veh2->getID()
     252              :                               << " laneIndex=" << veh2->getLane()->getIndex() << " numLanes=" << numLanes
     253              :                               << " alignment=" << toString(align) << "\n";
     254              : #endif
     255         2874 :                     std::vector<std::string> influencedBy = StringTokenizer(veh2->getParameter().getParameter(INFLUENCED_BY, "")).getVector();
     256         1437 :                     if (std::find(influencedBy.begin(), influencedBy.end(), myHolder.getID()) == influencedBy.end()) {
     257         1437 :                         influencedBy.push_back(myHolder.getID());
     258         2874 :                         const_cast<SUMOVehicleParameter&>(veh2->getParameter()).setParameter(INFLUENCED_BY, toString(influencedBy));
     259              :                     }
     260         2874 :                     veh2->getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM), "-1");
     261         1437 :                 }
     262              :             }
     263              : 
     264              :         } else { //if vehicle is passed all vehicles which had to react should get their state back after they leave the communication range
     265              :             if (myInfluencedVehicles.count(veh2->getID()) > 0) {
     266            2 :                 double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
     267            2 :                 if (distanceDelta > myReactionDist && veh.getID() != veh2->getID()) {
     268              :                     myInfluencedVehicles.erase(veh2->getID());
     269              :                     Parameterised::Map::iterator it = myInfluencedTypes.find(veh2->getID());
     270            0 :                     if (it != myInfluencedTypes.end()) {
     271              :                         // The vehicle gets back its old VehicleType after the emergency vehicle have passed them
     272            0 :                         resetVehicle(veh2, it->second);
     273              :                     }
     274              :                 }
     275              :             }
     276              :         }
     277              :     }
     278              :     // make upcoming junction foes slow down
     279        94642 :     for (MSLink* link : upcomingLinks) {
     280        29453 :         auto avi = link->getApproaching(&ego);
     281              :         MSLink::BlockingFoes blockingFoes;
     282        29453 :         link->opened(avi.arrivalTime, avi.arrivalSpeed, avi.arrivalSpeed, ego.getLength(),
     283        29453 :                      0, ego.getCarFollowModel().getMaxDecel(), ego.getWaitingTime(), ego.getLateralPositionOnLane(), &blockingFoes, true, &ego);
     284        29453 :         const SUMOTime timeToArrival = avi.arrivalTime - SIMSTEP;
     285        36860 :         for (const SUMOTrafficObject* foe : blockingFoes) {
     286         7407 :             if (!foe->isVehicle()) {
     287            0 :                 continue;
     288              :             }
     289         7407 :             const double dist = ego.getPosition().distanceTo2D(foe->getPosition());
     290         7407 :             if (dist < myReactionDist) {
     291         1933 :                 MSVehicle* microFoe = dynamic_cast<MSVehicle*>(const_cast<SUMOTrafficObject*>(foe));
     292         1933 :                 if (microFoe->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
     293              :                     // emergency vehicles should not react
     294            0 :                     continue;
     295              :                 }
     296         1933 :                 const double timeToBrake = foe->getSpeed() / SUMOVTypeParameter::getDefaultDecel();
     297         1933 :                 if (timeToArrival < TIME2STEPS(timeToBrake + 1)) {
     298              :                     // trigger emergency braking
     299          793 :                     const double decel = 0.5 * foe->getSpeed() * foe->getSpeed() / avi.dist;
     300              :                     std::vector<std::pair<SUMOTime, double> > speedTimeLine;
     301          793 :                     speedTimeLine.push_back(std::make_pair(SIMSTEP, foe->getSpeed()));
     302          803 :                     speedTimeLine.push_back(std::make_pair(SIMSTEP + TIME2STEPS(foe->getSpeed() / decel), 0));
     303          793 :                     microFoe->getInfluencer().setSpeedTimeLine(speedTimeLine);
     304              :                     //std::cout << SIMTIME << " foe=" << foe->getID() << " timeToBrake=" << timeToBrake << " timeToArrival=" << STEPS2TIME(timeToArrival) << " decel=" << decel << "\n";
     305          793 :                 }
     306              :             }
     307              :         }
     308        29453 :     }
     309        65189 :     return true; // keep the device
     310       130378 : }
     311              : 
     312              : 
     313              : void
     314         1384 : MSDevice_Bluelight::resetVehicle(MSVehicle* veh2, const std::string& targetTypeID) {
     315         1384 :     MSVehicleType* targetType = MSNet::getInstance()->getVehicleControl().getVType(targetTypeID);
     316              :     //targetType is nullptr if the vehicle type has already changed to its old vehicleType
     317         1384 :     if (targetType != nullptr) {
     318              : #ifdef DEBUG_BLUELIGHT_RESCUELANE
     319              :         std::cout << SIMTIME << " device=" << getID() << " reset " << veh2->getID() << "\n";
     320              : #endif
     321              : 
     322         2768 :         std::vector<std::string> influencedBy = StringTokenizer(veh2->getParameter().getParameter(INFLUENCED_BY, "")).getVector();
     323         1384 :         auto it = std::find(influencedBy.begin(), influencedBy.end(), myHolder.getID());
     324         1384 :         if (it != influencedBy.end()) {
     325              :             influencedBy.erase(it);
     326         2768 :             const_cast<SUMOVehicleParameter&>(veh2->getParameter()).setParameter(INFLUENCED_BY, toString(influencedBy));
     327              :         }
     328         1384 :         if (influencedBy.size() == 0) {
     329         1035 :             veh2->replaceVehicleType(targetType);
     330         3105 :             veh2->getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM),
     331         2070 :                                                     targetType->getParameter().getLCParamString(SUMO_ATTR_LCA_STRATEGIC_PARAM, "1"));
     332              :         }
     333         1384 :     }
     334         1384 : }
     335              : 
     336              : 
     337              : 
     338              : bool
     339         1072 : MSDevice_Bluelight::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     340              :     UNUSED_PARAMETER(veh);
     341              : #ifdef DEBUG_BLUELIGHT
     342              :     std::cout << SIMTIME << " device '" << getID() << "' notifyEnter: reason=" << toString(reason) << " enteredLane=" << Named::getIDSecure(enteredLane)  << "\n";
     343              : #else
     344              :     UNUSED_PARAMETER(reason);
     345              :     UNUSED_PARAMETER(enteredLane);
     346              : #endif
     347         1072 :     return true; // keep the device
     348              : }
     349              : 
     350              : 
     351              : bool
     352         1072 : MSDevice_Bluelight::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     353              :     UNUSED_PARAMETER(veh);
     354              : #ifdef DEBUG_BLUELIGHT
     355              :     std::cout << SIMTIME << " device '" << getID() << "' notifyLeave: reason=" << toString(reason) << " approachedLane=" << Named::getIDSecure(enteredLane) << "\n";
     356              : #else
     357              :     UNUSED_PARAMETER(reason);
     358              :     UNUSED_PARAMETER(enteredLane);
     359              : #endif
     360         1072 :     return true; // keep the device
     361              : }
     362              : 
     363              : 
     364              : void
     365          208 : MSDevice_Bluelight::generateOutput(OutputDevice* tripinfoOut) const {
     366          208 :     if (tripinfoOut != nullptr) {
     367          164 :         tripinfoOut->openTag("bluelight");
     368          328 :         tripinfoOut->closeTag();
     369              :     }
     370          208 : }
     371              : 
     372              : std::string
     373            0 : MSDevice_Bluelight::getParameter(const std::string& key) const {
     374            0 :     if (key == "reactiondist") {
     375            0 :         return toString(myReactionDist);
     376              :     }
     377            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     378              : }
     379              : 
     380              : 
     381              : void
     382            0 : MSDevice_Bluelight::setParameter(const std::string& key, const std::string& value) {
     383              :     double doubleValue;
     384              :     try {
     385            0 :         doubleValue = StringUtils::toDouble(value);
     386            0 :     } catch (NumberFormatException&) {
     387            0 :         throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
     388            0 :     }
     389            0 :     if (key == "reactiondist") {
     390            0 :         myReactionDist = doubleValue;
     391              :     } else {
     392            0 :         throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     393              :     }
     394            0 : }
     395              : 
     396              : 
     397              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1