Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-2024 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 Connection.h
15 : /// @author Daniel Krajzewicz
16 : /// @author Mario Krumnow
17 : /// @author Michael Behrisch
18 : /// @date 30.05.2012
19 : ///
20 : // C++ TraCI client API implementation
21 : /****************************************************************************/
22 : #pragma once
23 : #include <config.h>
24 :
25 : #include <vector>
26 : #include <map>
27 : #include <limits>
28 : #include <string>
29 : #include <sstream>
30 : #include <iomanip>
31 : #include <thread>
32 : #include <mutex>
33 : #include <foreign/tcpip/socket.h>
34 : #include <libsumo/Subscription.h>
35 :
36 :
37 : // ===========================================================================
38 : // global definitions
39 : // ===========================================================================
40 : #define PRECISION 2
41 :
42 :
43 : // ===========================================================================
44 : // class definitions
45 : // ===========================================================================
46 : namespace libtraci {
47 : /**
48 : * @class Connection
49 : * @brief C++ TraCI client API implementation
50 : */
51 : class Connection {
52 : public:
53 643 : static void connect(const std::string& host, int port, int numRetries, const std::string& label, FILE* const pipe) {
54 643 : myConnections[label] = new Connection(host, port, numRetries, label, pipe);
55 641 : }
56 :
57 1468903 : static Connection& getActive() {
58 1468903 : if (myActive == nullptr) {
59 50 : throw libsumo::FatalTraCIError("Not connected.");
60 : }
61 1468878 : return *myActive;
62 : }
63 :
64 : static bool isActive() {
65 4 : return myActive != nullptr;
66 : }
67 :
68 : static void switchCon(const std::string& label) {
69 655 : myActive = myConnections.find(label)->second;
70 : }
71 :
72 : const std::string& getLabel() const {
73 0 : return myLabel;
74 : }
75 :
76 : std::mutex& getMutex() const {
77 655188 : return myMutex;
78 : }
79 :
80 : /// @brief ends the simulation and closes the connection
81 : void close();
82 :
83 : libsumo::SubscriptionResults& getAllSubscriptionResults(const int domain) {
84 10727 : return mySubscriptionResults[domain];
85 : }
86 :
87 : libsumo::ContextSubscriptionResults& getAllContextSubscriptionResults(const int domain) {
88 29584 : return myContextSubscriptionResults[domain];
89 : }
90 :
91 : /// @name Command sending methods
92 : /// @{
93 :
94 : /** @brief Sends a SimulationStep command
95 : */
96 : void simulationStep(double time);
97 :
98 :
99 : /** @brief Sends a SetOrder command
100 : */
101 : void setOrder(int order);
102 :
103 : /** @brief Sends a GetVariable / SetVariable request if mySocket is connected.
104 : * Otherwise writes to myOutput only.
105 : * @param[in] cmdID The command and domain of the variable
106 : * @param[in] varID The variable to retrieve
107 : * @param[in] objID The object to retrieve the variable from
108 : * @param[in] add Optional additional parameter
109 : */
110 : void createCommand(int cmdID, int varID, const std::string* const objID, tcpip::Storage* add = nullptr) const;
111 :
112 :
113 : /** @brief Sends a SubscribeContext or a SubscribeVariable request
114 : * @param[in] domID The domain of the variable
115 : * @param[in] objID The object to subscribe the variables from
116 : * @param[in] beginTime The begin time step of subscriptions
117 : * @param[in] endTime The end time step of subscriptions
118 : * @param[in] domain The domain of the objects which values shall be returned (-1 means variable subscription)
119 : * @param[in] range The range around the obj to investigate (only meaningful for context subscription)
120 : * @param[in] vars The variables to subscribe
121 : * @param[in] params map of variable ids to parameters if needed
122 : */
123 : void subscribe(int domID, const std::string& objID, double beginTime, double endTime,
124 : int domain, double range, const std::vector<int>& vars, const libsumo::TraCIResults& params);
125 : /// @}
126 :
127 :
128 : tcpip::Storage& doCommand(int command, int var = -1, const std::string& id = "", tcpip::Storage* add = nullptr, int expectedType = -1);
129 : void addFilter(int var, tcpip::Storage* add = nullptr);
130 :
131 : void readVariableSubscription(int responseID, tcpip::Storage& inMsg);
132 : void readContextSubscription(int responseID, tcpip::Storage& inMsg);
133 : void readVariables(tcpip::Storage& inMsg, const std::string& objectID, int variableCount, libsumo::SubscriptionResults& into);
134 :
135 : private:
136 : /** @brief Validates the result state of a command
137 : * @param[in] inMsg The buffer to read the message from
138 : * @param[in] command The original command id
139 : * @param[in] ignoreCommandId Whether the returning command id shall be validated
140 : * @param[in] acknowledgement Pointer to an existing string into which the acknowledgement message shall be inserted
141 : */
142 : void check_resultState(tcpip::Storage& inMsg, int command, bool ignoreCommandId = false, std::string* acknowledgement = 0);
143 :
144 : /** @brief Validates the result state of a command
145 : * @return The command Id
146 : */
147 : int check_commandGetResult(tcpip::Storage& inMsg, int command, int expectedType = -1, bool ignoreCommandId = false) const;
148 :
149 : template <class T>
150 2 : static inline std::string toString(const T& t, std::streamsize accuracy = PRECISION) {
151 2 : std::ostringstream oss;
152 : oss.setf(std::ios::fixed, std::ios::floatfield);
153 2 : oss << std::setprecision(accuracy);
154 2 : oss << t;
155 2 : return oss.str();
156 2 : }
157 :
158 : template<typename T>
159 661 : inline std::string toHex(const T i, std::streamsize numDigits = 2) {
160 : // inspired by http://stackoverflow.com/questions/5100718/int-to-hex-string-in-c
161 661 : std::stringstream stream;
162 1322 : stream << "0x" << std::setfill('0') << std::setw(numDigits == 0 ? sizeof(T) * 2 : numDigits) << std::hex << i;
163 661 : return stream.str();
164 661 : }
165 :
166 : void readOutput();
167 :
168 : /** @brief Constructor, connects to the specified SUMO server
169 : * @param[in] host The name of the host to connect to
170 : * @param[in] port The port to connect to
171 : * @exception tcpip::SocketException if the connection fails
172 : */
173 : Connection(const std::string& host, int port, int numRetries, const std::string& label, FILE* const pipe);
174 :
175 : private:
176 : const std::string myLabel;
177 : FILE* const myProcessPipe;
178 : std::thread* myProcessReader;
179 : /// @brief The socket
180 : tcpip::Socket mySocket;
181 : /// @brief The reusable output storage
182 : mutable tcpip::Storage myOutput;
183 : /// @brief The reusable input storage
184 : mutable tcpip::Storage myInput;
185 :
186 : mutable std::mutex myMutex;
187 :
188 : std::map<int, libsumo::SubscriptionResults> mySubscriptionResults;
189 : std::map<int, libsumo::ContextSubscriptionResults> myContextSubscriptionResults;
190 :
191 : static Connection* myActive;
192 : static std::map<const std::string, Connection*> myConnections;
193 :
194 : private:
195 : /// @brief Invalidated assignment operator.
196 : Connection& operator=(const Connection&);
197 :
198 : };
199 :
200 : }
|