/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2012-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file Connection.h14/// @author Daniel Krajzewicz15/// @author Mario Krumnow16/// @author Michael Behrisch17/// @date 30.05.201218///19// C++ TraCI client API implementation20/****************************************************************************/21#pragma once22#include <config.h>2324#include <vector>25#include <map>26#include <limits>27#include <string>28#include <sstream>29#include <iomanip>30#include <thread>31#include <mutex>32#include <foreign/tcpip/socket.h>33#include <libsumo/Subscription.h>343536// ===========================================================================37// global definitions38// ===========================================================================39#define PRECISION 2404142// ===========================================================================43// class definitions44// ===========================================================================45namespace libtraci {46/**47* @class Connection48* @brief C++ TraCI client API implementation49*/50class Connection {51public:52static void connect(const std::string& host, int port, int numRetries, const std::string& label, FILE* const pipe) {53myConnections[label] = new Connection(host, port, numRetries, label, pipe);54}5556static Connection& getActive() {57if (myActive == nullptr) {58throw libsumo::FatalTraCIError("Not connected.");59}60return *myActive;61}6263static bool isActive() {64return myActive != nullptr;65}6667static void switchCon(const std::string& label) {68myActive = myConnections.find(label)->second;69}7071const std::string& getLabel() const {72return myLabel;73}7475std::mutex& getMutex() const {76return myMutex;77}7879/// @brief ends the simulation and closes the connection80void close();8182libsumo::SubscriptionResults& getAllSubscriptionResults(const int domain) {83return mySubscriptionResults[domain];84}8586libsumo::ContextSubscriptionResults& getAllContextSubscriptionResults(const int domain) {87return myContextSubscriptionResults[domain];88}8990/// @name Command sending methods91/// @{9293/** @brief Sends a SimulationStep command94*/95void simulationStep(double time);969798/** @brief Sends a SetOrder command99*/100void setOrder(int order);101102/** @brief Sends a GetVariable / SetVariable request if mySocket is connected.103* Otherwise writes to myOutput only.104* @param[in] cmdID The command and domain of the variable105* @param[in] varID The variable to retrieve106* @param[in] objID The object to retrieve the variable from107* @param[in] add Optional additional parameter108*/109void createCommand(int cmdID, int varID, const std::string* const objID, tcpip::Storage* add = nullptr) const;110111112/** @brief Sends a SubscribeContext or a SubscribeVariable request113* @param[in] domID The domain of the variable114* @param[in] objID The object to subscribe the variables from115* @param[in] beginTime The begin time step of subscriptions116* @param[in] endTime The end time step of subscriptions117* @param[in] domain The domain of the objects which values shall be returned (-1 means variable subscription)118* @param[in] range The range around the obj to investigate (only meaningful for context subscription)119* @param[in] vars The variables to subscribe120* @param[in] params map of variable ids to parameters if needed121*/122void subscribe(int domID, const std::string& objID, double beginTime, double endTime,123int domain, double range, const std::vector<int>& vars, const libsumo::TraCIResults& params);124/// @}125126127tcpip::Storage& doCommand(int command, int var = -1, const std::string& id = "", tcpip::Storage* add = nullptr, int expectedType = -1);128void addFilter(int var, tcpip::Storage* add = nullptr);129130void readVariableSubscription(int responseID, tcpip::Storage& inMsg);131void readContextSubscription(int responseID, tcpip::Storage& inMsg);132void readVariables(tcpip::Storage& inMsg, const std::string& objectID, int variableCount, libsumo::SubscriptionResults& into);133134private:135/** @brief Validates the result state of a command136* @param[in] inMsg The buffer to read the message from137* @param[in] command The original command id138* @param[in] ignoreCommandId Whether the returning command id shall be validated139* @param[in] acknowledgement Pointer to an existing string into which the acknowledgement message shall be inserted140*/141void check_resultState(tcpip::Storage& inMsg, int command, bool ignoreCommandId = false, std::string* acknowledgement = 0);142143/** @brief Validates the result state of a command144* @return The command Id145*/146int check_commandGetResult(tcpip::Storage& inMsg, int command, int expectedType = -1, bool ignoreCommandId = false) const;147148template <class T>149static inline std::string toString(const T& t, std::streamsize accuracy = PRECISION) {150std::ostringstream oss;151oss.setf(std::ios::fixed, std::ios::floatfield);152oss << std::setprecision(accuracy);153oss << t;154return oss.str();155}156157template<typename T>158inline std::string toHex(const T i, std::streamsize numDigits = 2) {159// inspired by http://stackoverflow.com/questions/5100718/int-to-hex-string-in-c160std::stringstream stream;161stream << "0x" << std::setfill('0') << std::setw(numDigits == 0 ? sizeof(T) * 2 : numDigits) << std::hex << i;162return stream.str();163}164165void readOutput();166167/** @brief Constructor, connects to the specified SUMO server168* @param[in] host The name of the host to connect to169* @param[in] port The port to connect to170* @exception tcpip::SocketException if the connection fails171*/172Connection(const std::string& host, int port, int numRetries, const std::string& label, FILE* const pipe);173174private:175const std::string myLabel;176FILE* const myProcessPipe;177std::thread* myProcessReader;178/// @brief The socket179tcpip::Socket mySocket;180/// @brief The reusable output storage181mutable tcpip::Storage myOutput;182/// @brief The reusable input storage183mutable tcpip::Storage myInput;184185mutable std::mutex myMutex;186187std::map<int, libsumo::SubscriptionResults> mySubscriptionResults;188std::map<int, libsumo::ContextSubscriptionResults> myContextSubscriptionResults;189190static Connection* myActive;191static std::map<const std::string, Connection*> myConnections;192193private:194/// @brief Invalidated assignment operator.195Connection& operator=(const Connection&);196197};198199}200201202